作用域是指变量的合法使用范围。
例如下图中,函数fn3内定义的变量a3,无法在函数fn3以外的区域使用。

作用域分为全局作用域,函数作用域,块级作用域(ES6新增)
a。if、while、for等大括号{}内的区域称为块级作用域。
自由变量是指一个变量在当前作用域没有定义,但是被使用了。当前作用域中没有该变量,会向上级作用域,一层一层依次寻找,直到找到为止。
如果向上寻找一直找到全局作用域都没找到,则会报错xxx is not defined

闭包是作用域应用的特殊情况,有两种表现:函数作为返回值,函数作为参数被传递。
闭包的影响:闭包中的变量,在闭包执行结束后,依然留存在内存中,得不到释放。会影响性能。
所有自由变量的查找,是在函数定义的地方,向上级作用域查找,不是在执行的地方进行查找。
function create(){
const a = 100
return function(){
console.log(a)
}
}
const fn = create()
const a = 200
fn() // 函数的执行结果为 100
function print(fn){
const a = 200
fn()
}
const a = 100
function fn(){
console.log(a)
}
print(fn) // 打印的结果是 100
在 JavaScript 中,this 关键字用于引用当前正在执行的函数所属的对象。this取什么值,是在函数执行的时候确定的,不是在函数定义的时候确定的。
场景1:普通函数的this指向
function fn1(){
console.log(this)
}
fn1()
普通函数的this指向Window

场景2:使用call apply bind调用
function fn1(){
console.log(this)
}
fn1()
fn1.call({x: 100})
const fn2 = fn1.bind({x: 200})
fn2()
this指向call、apply、bind中传入的对象。call和apply调用函数会直接返回结果,但是bind不会直接返回结果,需要将返回值赋给一个新的函数,再执行该函数。

场景3:作为对象的方法被调用
const zhangsan = {
name: '张三',
sayHi(){
console.log(this)
},
wait(){
setTimeout(function(){
console.log(this)
})
},
waitAgain(){
setTimeout(()=>{
console.log(this)
})
}
}
zhangsan.sayHi() // this指向当前对象
zhangsan.wait() // this指向 window
zhangsan.waitAgain() // this指向当前对象

箭头函数的this不是在函数运行时确定的,是在函数定义时确定的,箭头函数没有自己的this,它们继承父级作用域中的 this。
场景4:在class方法中被调用
class People{
constructor(name){
this.name = name
this.age = 20
}
sayHi(){
console.log(this)
}
}
const lisi = new People('李四')
lisi.sayHi()

实现一个简单的cache工具。
下面代码,无法直接修改data中的数据,需要调用set和get方法才能修改,因为data的作用域在函数内,因此可以隐藏data的数据。
function createCache(){
const data = {} // 闭包中的数据,被隐藏,不被外界访问
return {
set: function(key, val){
data[key] = val
},
get:function(key){
return data[key]
}
}
}
const c = createCache()
c.set('a', 100)
console.log(c.get('a')) // 100
// 创建 10 个 '' 标签,点击的时候弹出来对应的序号
let a
for(let i = 0; i < 10; i++){
a = document.createElement('a')
a.innerHTML = i + '
'
a.addEventListener('click', function(e){
e.preventDefault()
alert(i)
})
document.body.appendChild(a)
}
