关于JavaScript 闭包大多认可的解释是:
JavaScript 闭包的本质源自两点,词法作用域和函数当作值传递。
词法作用域,就是,按照代码书写时的样子,内部函数可以访问函数外面的变量。引擎通过数据结构和算法表示一个函数,使得在代码解释执行时按照词法作用域的规则,可以访问外围的变量,这些变量就登记在相应的数据结构中。
函数当作值传递,即所谓的first class对象。就是可以把函数当作一个值来赋值,当作参数传给别的函数,也可以把函数当作一个值 return。一个函数被当作值返回时,也就相当于返回了一个通道,这个通道可以访问这个函数词法作用域中的变量,即函数所需要的数据结构保存了下来,数据结构中的值在外层函数执行时创建,外层函数执行完毕时理因销毁,但由于内部函数作为值返回出去,这些值得以保存下来。而且无法直接访问,必须通过返回的函数。这也就是私有性。
但是关于闭包的概念,其实还有其他的说法:
《javascript权威指南》 (第六版)第8章第6节:从技术的角度讲,所有的JavaScript函数都是闭包:它们都是对象,它们都关联到作用域链。
参照这个概念的话,那么所有函数都是闭包;
《javascript高级程序设计》(第三版)第7章第2节:闭包是指有权访问另一个函数作用域中的变量函数;(以上两段定义引用来自:怎么更好的理解JS闭包,希望举个例子、还有应用场景? – 前端开发)
这么说的话,函数里面的函数就是闭包(其实这条定义也能证明每个函数都是闭包,毕竟函数外面就是全局对象);
比如:
function a() {
var a = 0;
function b(x) {
a = a + x;
}
b(1);
console.log(a);
}
a();
那么b()就是闭包;
可是百度百科里以及很权威的博客有一句话:“当其中一个内部函数在包含它的外部函数之外被调用时,就会形成闭包。”
也就是说函数里的函数不一定是闭包,必须在包含它的外部函数之外被调用时,就会形成闭包。这里的解释也正符合本文一开始对闭包的理解,既有词法作用域,也有函数作为参数传递的过程。
即上例改成这样才是闭包:
function a() {
var a = 0;
function b(x) {
a = a + x;
console.log(a);
}
return b;
}
a()(1);
所以我觉得闭包这东西概念上还是有些模糊,不同的人理解不同得出的答案也不同。可能是站在的角度不同吧。权威指南6与高级程序设计可能是是从闭包概念根本出发的结论,但是如果说每个函数都是闭包,我们可能会不甘心;而百度百科那一段可能是从js运用角度总结出的概念,这么看其实百度百科这段话结合本文开始的理解说不定是大家所想要的答案。
其实闭包这东西即便是很多人的理解不同,但是都自觉不自觉的用过,而且用的基本都对还都很完美。会用就好,反正你用错了代码也会报错。。。
PS:我发现实际运用中,js的闭包还是想要实现封装这个功能的,js里闭包的很多运用跟c#里的属性:get、set差不多~
所以我觉得我们应该先把闭包与js实现封装区分开来对待,因为很多面试问闭包也是想从你口中听到封装之类的字眼(我不是说闭包就是用来实现封装哈,闭包还有很多其他用途,比如for循环中保存click事件的那个功能,这个跟封装概念不一样,如果我理解错误请批评指出)。
所以这两个概念先区分开的比较好。
当然还要区分的就是立即执行函数与闭包的概念,我之前就以为立即执行函数那样的就是闭包,哈哈。