您好,登錄后才能下訂單哦!
首先,一個函數不管是不是匿名函數,和閉包之間根本沒有任何關系!
所謂閉包究竟是什么?網絡上說法云里霧里,講得高深莫測,但是其實只要稍微有一些編譯器實現機制的認識,就會知道閉包其實是非常簡單的東西。
我們先來看看下面的代碼:
function funcA() { var a = 1, b = 2; return funcB(); function funcB() { // 注意,a 和 b 在本函數里根本沒有定義,但是竟然能訪問到 return a + b; } } var a = funcA(); // a 將會等于 3 |
上面的代碼神奇的地方有幾點:
1、函數可以嵌套定義(而 C/C++ 就不行)
2、嵌套的函數可以訪問到它的上級函數的局部變量
先說嵌套,其實這個能力沒什么神奇的,C/C++ 編譯器稍作修改就能支持,但是這么實現出來,雖然函數可以嵌套了,實用價值還是比較小,因為訪問不到上級函數的局部變量啊。而且我們知道 Javascript 的嵌套函數是可以層層嵌套的,而訪問時最內層的函數也能夠訪問到最頂層的函數的變量,非常有用!
說到這里,和閉包有什么關系呢?
閉包,就是用來實現這種嵌套時還能夠層層向上訪問變量的功能的!對的,它就是一個簡單的編譯器技巧,用來使得內部函數能夠訪問上級函數的變量。
簡單來說,它具體實現的方法為,在每個函數上附加上一個額外的隱藏對象,這個對象其實就叫做閉包對象,你別管他名字怎么叫,它就是個普通的對象!它沒什么神奇的,就是記錄了本函數內部的變量列表而已。而且這個閉包對象還保存了一個指向上級函數的閉包對象的引用。
這樣一來,就形成了一個鏈條。當我們在一個函數里訪問一個變量的時候,編譯器會先看看在本閉包里到底有沒有這個變量,如果沒有就向上尋找。如果找到,那就用,如果一直找到頭也沒有,那就提示出錯。
明白了嗎?就是這么回事。但是最后還有一點,按照上面的方式構造出來的閉包好像是固定的,其實每次調用一個函數的時候,都會單獨創建一個新的閉包對象和這一次調用對應起來。因此其實閉包鏈是動態創建的。
其實要說清楚這個問題,得配幾個圖。但是時間所限,我就不細說了。如果你能理解那最好,如果還是有疑問,那你以后慢慢接觸得多了就知道了。
最后解釋一下這段代碼,加深理解
function X() { return function () { // ... } } |
注意X里面這里返回了一個匿名函數。一定要記住這個函數由于是嵌套定義在 X 里的,因此它的閉包對象是鏈接到 X 的閉包對象上的,所以在這個匿名函數里是可以訪問到 X 內部的變量的。其實就是這么簡單。不管你嵌套多少層,匿名還是有名。我只看你定義時的嵌套關系,就知道閉包鏈的整個鏈條!其他就順理成章了。
最后推薦兩個讓你走出國內普遍存在的誤區的方法,一是多看 ECMA-262, 5e,這里面包含了所有標準化的 Javascript 的算法實現細節。另外一個是研究 Google 的 v8 引擎。自己下代碼下來編譯調試下,很多問題就能搞清楚了。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。