大家好,金三银四马上也快到了,有没有小伙伴们跃跃欲试了,咱们可以一起交流下。今天还是来回顾下不管什么阶段的开发者可能面试都会碰到的一道题,一个很经典却永不过时的一个知识点闭包
。
在以前呢,也是看过许许多多的闭包类的文章,不过这次还是给记录下来吧,方便后期随时用。
那为什么要方便后期随时用呢,因为我发现用了它好几年了,多多少少还是理解不到位😭。
给大家看下我的理解,在面试中碰到闭包问题,应该有怎么样的思路进行回答
大家先来看下这道题,看下是否能看出来输出结果
var data = [];
for (var i = 0; i < 3; i++) {
data[i] = function () {
console.log(i);
};
}
data[0](); // 输出结果
data[1](); // 输出结果
data[2](); // 输出结果
优雅永不过时,答对了说明你对闭包还是有一定研究的,没答对的继续往下看
那我们先来看看闭包的概念,什么是闭包,看看MDN与高级程序设计给出的概念
- 能够访问其它函数内部变量的函数,称为闭包
- 能够访问自由变量的函数,称为闭包
那我们来分析下上边的例题
在分析之前你需要对作用域以及执行上下文有一定的了解,如果不太明确的话,可以优先看下这两篇文章
再继续阅读下面内容
var data = [];
for (var i = 0; i < 3; i++) {
data[i] = function () {
console.log(i);
};
}
data[0](); // 输出结果
data[1](); // 输出结果
data[2](); // 输出结果
首先我们记录下这道例题的执行上下文栈的变化
-
首先进入了全局执行上下文,然后创建全局执行上下文,将全局上下文放入执行上下文栈中
-
然后继续初始化执行全局上下文,创建作用域链以及变量对象等
那么此时的全局上下文VO为
globalContext = { VO: { data: [...], i: 3 } }
-
执行
data[0]()
,然后创建data[0]()
执行上下文,继续放入执行上下文栈内 -
然后呢初始化
data[0]()
执行上下文,创建作用域链以及变量对象等那么此时的
data[0]()
AO为data[0]Context = { AO: { arguments: {length: 0} } }
那么此时的
data[0]()
作用域链为data[0]Context = { Scope: [AO, globalContext.VO] }
因为在
data[0]Context
活动对象AO中是没有i值的,所以去全局上下文的变量对象中查找,此时全局上下文的变量对象中i值为3所以
data[0]()
输出结果为3 -
执行完毕后在
data[0]()
执行上下文在执行上下文栈给弹出 -
至于
data[1]()
与data[2]()
与步骤3-5是一样的,所以在这就不多说了
至于闭包的使用场景,其实在日常开发中使用到是非常频繁的
- 防抖节流函数
- 定时器回调
- 等就不一一列举了
闭包帮我们解决了什么问题呢
内部变量是私有的,可以做到隔离作用域,保持数据的不被污染性
同时闭包也带来了不小的坏处
说到了它的优点内部变量是私有的,可以做到隔离作用域
,那也就是说垃圾回收机制是无法清理闭包中内部变量的,那最后结果就是内存泄漏