什么是闭包,为什么使用闭包
# 什么是闭包
在 JS 忍者秘籍(P90)中对闭包的定义:闭包允许函数访问并操作函数外部的变量。
红宝书上对于闭包的定义:闭包是指有权访问另外一个函数作用域中的变量的函数。
MDN 对闭包的定义为:闭包是指那些能够访问自由变量的函数。这里的自由变量是外部函数作用域中的变量。
第二种定义相对更好理解一些,闭包,本质就是上级作用域内变量的生命周期,因为被下级作用域内引用,而没有被释放。就导致上级作用域内的变量,等到下级作用域执行完以后才正常得到释放。
# 形成闭包的原因
原因
内部的函数存在外部作用域的引用就会导致闭包。
解释闭包是怎么形成的,或是对闭包的理解,可以从执行上下文、执行栈、作用域链来切入:
常见的两种闭包形式: 一种是在一个函数A中又声明了一个函数B,然后还是在函数A中直接调用了函数B。另一个种是函数A返回了一个函数B,最终调用B的位置是在函数A外面。
第一种:
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
debugger
var name = 'mine'
return scope;
}
return f();
}
checkscope();
2
3
4
5
6
7
8
9
10
11
可以明显的看到,函数f的作用域(也就是f可访问到的变量)包括 自身中定义的变量、函数checkscope中的变量、全局变量。其中Closure就是对函数checkscope作用域的一种引用,也就是闭包。
第二种:
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
var name = 'mine'
debugger
return scope;
}
return f;
}
checkscope()();
2
3
4
5
6
7
8
9
10
11
12
13
对比以下,发现这两种情况,函数f的作用域一模一样。
区别在于,这两种情况下,函数f执行的时候,整个程序的执行栈不同,第二种情况,函数f执行的时候,函数checkscope已经执行完了,已经从执行栈中退出并且被销毁了,但是由于函数f还保留着对函数checkscope中变量的引用(闭包的存在),所以checkscope中的变量并没有被销毁,函数f还是可以访问到定义在checkscope中的变量。
# 参考文章链接
JS 闭包经典使用场景和含闭包必刷题 (opens new window)
我从来不理解JavaScript闭包,直到有人这样向我解释它 (opens new window)
JS-原生/一个例子讲清楚什么是闭包,什么是内存销毁 (opens new window)
从JS堆栈内存和垃圾回收来理解闭包 (opens new window)