1. 作用域
作用域是指变量的合法使用范围。
例如下图中,函数fn3
内定义的变量a3
,无法在函数fn3
以外的区域使用。
作用域分为全局作用域,函数作用域,块级作用域(ES6新增)
- 全局作用域:变量没有受到函数的约束,在全局中都可以使用,例如图中的变量
a
。 - 函数作用域:在函数中定义的变量,只能在当前函数中使用。
- 块级作用域:
if、while、for
等大括号{}
内的区域称为块级作用域。
2. 自由变量
自由变量是指一个变量在当前作用域没有定义,但是被使用了。当前作用域中没有该变量,会向上级作用域,一层一层依次寻找,直到找到为止。
如果向上寻找一直找到全局作用域都没找到,则会报错xxx is not defined
3. 闭包
闭包是作用域应用的特殊情况,有两种表现:函数作为返回值,函数作为参数被传递。
所有自由变量的查找,是在函数定义的地方,向上级作用域查找,不是在执行的地方进行查找。
- 函数作为返回值
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
4. 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指向当前对象
场景4:在class方法中被调用
class People{
constructor(name){
this.name = name
this.age = 20
}
sayHi(){
console.log(this)
}
}
const lisi = new People('李四')
lisi.sayHi()
5. 实际开发中闭包的应用
5.1 隐藏数据
实现一个简单的cache工具
5.2 点击标签跳出相应数字
// 创建 10 个 '<a>' 标签,点击的时候弹出来对应的序号
let a
for(let i = 0; i < 10; i++){
a = document.createElement('a')
a.innerHTML = i + '<br>'
a.addEventListener('click', function(e){
e.preventDefault()
alert(i)
})
document.body.appendChild(a)
}