不知道閉包算不算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++而來的。
用這兩個例子可以清楚的理解什么是閉包,用什么樣的方式來解決閉包帶給我的不想要的效果。再次總結一下,想要形成閉包,需要有一個函數訪問了另一個函數作用域里的變量並添加為自己的活動對象。這樣就導致變量不再是值傳遞而是就是同一個變量了。解決方式就是在添加一個可以值傳遞的匿名函數來取得值傳遞的結果。
我的理解就是介個樣子的啦,正在做一些題目來驗證我的理解是否正確,拜拜~
