一、什么是闭包
这里引用技术蛋老师的一句话,闭包就好比,我们把一本书放到书包里,然后把拉链拉起来,我们什么时候想看,再拉开拉链就行了
先看一个例子:
function books(){
var book="书包里的书";
}
console.log(book);
以上代码,很显然不能输出结果,这是为什么呢?
原因:从执行上下文的角度来看:全局上下文中,要求在控制台输出"book"变量,但是全局中并没有book变量,虽然有books这个函数,但是并没有执行这个函数,所以不会输出正确结果;
二、执行上下文
我们执行JS代码的时候,会生成执行上下文,执行上下文,也就是执行环境;
执行上下文(执行环境):全局环境、函数环境、Eval环境
JS代码机制:单线程(一次只能做一个事),JS执行上下文的处理模式就是栈
理解闭包,一定要理解作用域链
执行上下文,分为创建阶段和执行阶段
创建阶段:创建作用域链【当前变量对象+所有父级变量对象】、变量对象【参数、变量、函数声明】、this
执行阶段:变量赋值、函数引用等
三、经典面试题
for(var i=0;i<5;i++){
setTimeout(function(){
console.log(i++)
,4000);
}
console.log(i);
输出结果,5,5,6,7,8,9
原因:
说明:setTimeout(),即使设置毫秒数为0,JS也不会立马执行函数,而是放在任务队列中
因此任务队列中,有5个等待输出的i++
匿名函数,可以访问到外部i的值,所以此时的i=5,第一次输出5
此时全局上下文没有需要执行的任务了,因此就开始执行任务队列中的任务,因此会依次输出,5,6,7,8,9
注意,setTimeout为4s,指的是,执行栈执行完所有任务后,间隔4s后,再执行任务队列中的任务
像这种,把函数作为指,放到任务队列,然后在规定时间内回调,就是创建了一个闭包,也是我们常说的回调函数
重点!!如何改成依次输出5,0,1,2,3,4?
修改成这样子就可以了:
for(var i=0;i<5;i++){
(function(j){
setTimeout(function(){
console.log(j++)
},4000);
)(i)
console.log(i);
解释:
实现会创建全局执行上下文,毫无疑问,一开始输出的值是i=5
然后再到立即执行函数执行上下文,此时并不会立即执行,而是放到任务队列中,j=0
继续再到立即执行函数执行上下文,此时不会立即执行,放到任务队列。j=1
....
最后到全局执行上下文,发现没有要执行的任务了,就开始执行任务队列中的任务,依次输出0,1,2,3,4
本人根据B站的技术蛋老师讲解视频整理得出,如有写错的地方,欢迎指出~