闭包
本文最后更新于:1 年前
闭包
当内部函数被返回到外部并保持时,一定会产生闭包,闭包会产生原来的作用域链不释放,
过度的闭包可能会导致内存泄漏或加载过慢
1 |
|
什么是闭包
函数嵌套函数,内部函数就是闭包。就是能够访问其他函数内部变量的函数。
闭包可以做数据缓存
- 封装一段代码利用闭包实现模块化功能,读取/设置一个函数内部的私有变量
- 让变量的值始终保持在内存中
普通闭包
add和reduce函数属于同级,两个的AO互不干扰,不能互相访问。但是都有上一级test的AO,可以同时访问test的变量1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19function test() {
let n = 100
function add() {
n++
console.log(n)
}
function reduce() {
n--
console.log(n)
}
return [add, reduce] //返回两个函数
}
let arr = test()
arr[0]()
arr[1]()
arr[1]()
//101
//100
//99对象闭包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18function test() {
let num = 0
let compute = {
add: function () {
num++
console.log(num)
},
minus: function () {
num--
console.log(num)
},
}
return compute
}
let compute = test()
compute.add() //1
compute.add() //2
compute.minus() //1构造函数闭包
构造函数被实例化时,内部产生一个this,最后隐式返回this1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16function Compute() {
let num = 10
this.add = function () {
num++
console.log(num)
}
this.minus = function () {
num--
console.log(num)
}
//return this //构造函数被实例化时,内部产生一个this,最后隐式返回this
}
let compute = new Compute()
compute.add() //11
compute.add() //12
compute.minus() //11闭包中的this对象
在闭包中使用 this 会让代码变复杂。
如果内部函数没有使用箭头函数定义,则 this 对象会在运行时绑定到执行函数的上下文。
如果在全局函数中调用,则 this 在非严格模式下等于 window,在严格模式下等于 undefined。
如果作为某个对象的方法调用,则 this 等于这个对象。
匿名函数在这种情况下不会绑定到某个对象,这就意味着 this 会指向 window,除非在严格模式下 this 是 undefined。
不过,由于闭包的写法所致,这个事实有时候没有那么容易看出来。
1 |
|
为什么匿名函数没有使用其包含作用域(getIdentityFunc()
)的 this 对象呢?
每个函数在被调用时都会自动创建两个特殊变量:this 和 arguments。内部函数永远不可能直接访问外部函数的这两个变量。但是,如果把 this 保存到闭包可以访问的另一个变量中, 则是行得通的。
1 |
|
在定义匿名函数之前,先把外部函数的 this 保存到变量 that 中。然后在定义闭包时,就可以让它访问 that,因为这是包含函数中名称没有任何冲突的一个变量。即使在外部函数返回之后,that 仍然指向 object,所以调用 object.getIdentityFunc()()
就会返回”My Object”
闭包必需了解的问题
引用的变量可能发生变化
以下代码输出什么
1 |
|
为什么打印出来都是3?
循环可以改写成
1 |
|
循环结束后等价于
1 |
|
此时 i 的值已经为 3 ,所以当 data[0]、data[1]、data[2] 中任意一个执行时输出结果都为 3。
利用闭包解决:
1 |
|
当然更简单的方法就是使用 let 声明变量。
this指向问题
匿名函数在这种情况下不会绑定到某个对象,这就意味着 this 会指向 window,除非在严格模式下 this 是 undefined。
1 |
|
IE中内存泄露问题
1 |
|
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!