闭包是js中炙手可热的一块洋芋,它一直是前端面试js时的重难点
什么是闭包?
闭包是一种现象,指的是那些引用了其他函数作用域下的变量的函数(js红宝书原文)。通常是在嵌套函数中出现的(套娃)
产生的原因:js的作用域链机制和垃圾回收机制
正常的函数的执行过程(没套娃)
let a=1;
let b=2;
function add(num1,num2){
return num1+num2;
}
let result=add(a,b);
上代码块在全局作用域下定义了一个add方法,希望传进来俩个变量并相加
定义了a,b俩变量并赋值
然后调用add函数并赋值给result。
让我们来看看这个过程中作用域链和执行上下文都有什么动静
**首先,全局环境下定义add函数,**这个时候准备为add函数创建作用域,预装载全局变量对象,并保存在内部的[[scope]]
中
调用add函数,创建了add函数的执行上下文,通过复制函数的[[scope]]
并真正创建了一个作用域链,
然后,用arugument(不是箭头),和num1,num2来初始化这个函数的活动对象,在它的作用域链上添加这个活动对象(置于作用域顶部
)
如下图
这样一来,add函数的作用域链就ok了,就是add函数->全局global(node环境下)
add函数执行完毕后,它的活动对象就被销毁,然后内存下只剩下全局作用域
但如果add函数没在它自己的函数内部找到要的变量呢?
函数内部代码访问变量时,就按着作用域链根据标识符去寻找,找到就停止。
套娃的函数的执行过程
function outer(outerName){
return function(){
console.log(outerName);
}
}
let result=outer("马云");
result();
上面代码块中定义了一个outer函数,它希望一个得到参数outerName
在outer函数内部return了一个匿名函数,调用这个匿名函数会输出outerName
然后定义了result变量接收outer函数调用返回值(匿名函数),然后调用这个返回值
让我们来看看这个过程中作用域链和执行上下文都有什么动静
按照之前的思路我们可以得到下图
这样一来匿名函数找不到这个outerName,然后沿着作用域链找,在outer的活动对象中找到了
然后就输出这个值,但是outer的活动对象不会被销毁,因为匿名函数的作用域链中仍然有对他的引用(outerName)
直到匿名函数被销毁
总结一下闭包(入门级):
闭包是一种现象,指的是一个内部函数引用了外部函数作用域下的变量从而导致外部函数作用域不会被销毁的现象。
产生的原因:函数作用域,作用域链机制和垃圾回收机制