在理解js作用域和作用域链之后,(https://blog.csdn.net/timcope/article/details/80103538)我们可以去探究闭包。
function a (){
function b(){
console.log(aaa);
}
var aaa =123;
return b;
}
var demo =a();
demo();
[闭包的概念]
上面的代码就是典型的一个闭包,当一个函数的内部函数被保存到外部,必定会出现闭包。闭包的定义在js学习中一直是非常模糊的,可以说每个人对于闭包的理解是不同的,我认为闭包的是作用域的产物,姑且认为闭包是指一个可以访问另一个函数作用域中变量的函数。
[为什么会形成闭包]
当a函数被定义时,a会产生执行期上下文,a.[[scope]] ->scope chain[0]->Global Object
接下去a函数执行 a.[[scope]]->scope chain[0] ->Activation Object scope chain[1]->Global Object 。
而当b被定义时,由于b在函数a内被定义它可以访问a的作用域,使以b的作用域链上天生就有a的作用域链 b产生的执行期上下文为 b.[[scope]]->scope chain[0] ->Activation Object(这是a的AO) scope chain[1]->Global Object 。
执行至return b时 b被保存到外部被demo变量接受。
a执行完毕之后,会销毁自身的执行期上下文, 也就是销毁a.[[scope]]->scope chain[0] ->Activation Object。
但是b函数被保存到外部并执行,它的作用域链上有b.[[scope]]->scope chain[0] ->Activation Object(b的AO)->scope chain[1] ->Activation Object(这是a的AO) scope chain[2]->Global Object
也就是说当b函数访问aaa变量时,会沿着作用域链找到 a函数中的变量aaa且值为123;在外部的一个函数访问到了一个函数内部的变量,这就是闭包。本质是闭包导致了a原有的作用域链得不到释放。
[闭包的危害]
我们经常会说闭包会导致原有作用域链不释放,造成内存泄漏。什么叫内存泄漏呢,内存泄露是指你用不到(访问不到)的变量,依然占居着内存空间,不能被再次利用起来。我们可以发现我们上面的闭包,并不存在内存泄漏,因为aaa变量是我们需要的,当a函数内存在其他我们不需要的变量,这才叫内存泄漏。
[闭包的作用]
1.可以实现封装,属性私有化 (这个在后面我会另外解释)
2.模块化开发,防止全局变量(以后写到模块化时再说吧)
3.可以做缓存(例如上面例子中的aaa变量,它并没有被清除,而是一直保存在计算机内存中)