不知道闭包算不算js的难点,反正我在闭包这一部分花了很多时间,不过幸运的是还是有很多收获的。我不知道我的理解是不是正确,不过把我自己的理解分享一下,如果那里有不对的地方,还希望大家可以告诉我,让我赶快改正呢~
《Javascript高级程序设计》上对闭包的定义是:有权限访问另一个函数作用域中的变量的函数。也就是说,闭包是一个函数,那什么样的函数才能是闭包呢?他能访问另一个函数作用域中的变量。这样的解释让我们直接想起了一个函数的内部函数,因为根据作用域链的规则,只有嵌套的函数才能达到这个效果。并且这个闭包函数是作为父函数的返回值返回,而且这个闭包函数通常是个匿名函数。
可能说这么多的书面语依旧很晦涩难懂,所以嘞,就举个例子来帮助理解。
1 function createFunction(){ 2 var result = new Array(); 3 for(var i=0;i<10;i++){ 4 result[i] = function(){ 5 return i; 6 }; 7 } 8 return result; 9 }
PS:例子来源于《Javascript 高级程序设计》一书,但代码解释是根据我的理解,有什么不对的地方好iaxiwnagdajia可以指出来,谢谢~
首先 i 是 createFunction 的活动对象,但被一个匿名函数使用并作为返回值而形成闭包。因为匿名函数需要将i 返回,所以i同样被添加为匿名函数的活动对象,也就是 i<10 中的 i,和 return i 中的i 是同一个 i 而并非一般情况下的值传递。而 createFunction 返回时, i的值必然已经成为10了,前面已经说了i 是同一个i 那匿名函数内部的 i也是10 了。
再看一段常用解决方案的代码
function createFunction(){ var result = new Array(); for(var i=0;i<10;i++){ result[i] = function(num){ return function(){ return num; }; }(i); } return result; }
上面这段代码添加了另一个有参的匿名函数。与上面代码相同的是无参的匿名函数因为返回了父函数的变量,所以把父函数的num活动对象添加为自己的活动对象,但有参匿名函数的num是由createFunction逐次引用而来的(因为值传递的缘故,createFunction返回之前的所有i++都被记录在了num里)。所以num值为从0到9 逐次i++而来的。
用这两个例子可以清楚的理解什么是闭包,用什么样的方式来解决闭包带给我的不想要的效果。再次总结一下,想要形成闭包,需要有一个函数访问了另一个函数作用域里的变量并添加为自己的活动对象。这样就导致变量不再是值传递而是就是同一个变量了。解决方式就是在添加一个可以值传递的匿名函数来取得值传递的结果。
我的理解就是介个样子的啦,正在做一些题目来验证我的理解是否正确,拜拜~