摘要:總結閉包的作用域鏈如下圖通過上述分析我們還可以看出,閉包有一個不同于普通函數的特性,就是它會攜帶包含它的函數的作用域,因此會占用更多內存。
閉包的作用域鏈
閉包是有權訪問另一個函數作用域中的變量的函數,比如:
function createFunc(words) { return function() { return words; } } var func = createFunc("Hello World!") func(); // "Hello World!"
上述例子中createFunc的返回值是一個函數(閉包),這個返回值在調用時仍然可以訪問createFunc的words屬性,這是為什么呢?還記得在之前的文章Javascript 變量、作用域和內存問題中提到的,一個函數在創建時,會生成一個內部屬性[[scope]],這個屬性包含函數被創建的作用域中對象的集合,也就包括了createFunc的活動對象,而如果沒有閉包,createFunc的活動對象在調用結束時就可以進入GC序列,只有銷毀對閉包的引用,即func = null,才會使createFunc的活動對象被GC。
總結閉包的作用域鏈如下圖:
通過上述分析我們還可以看出,閉包有一個不同于普通函數的特性,就是它會攜帶包含它的函數的作用域,因此會占用更多內存。
閉包與變量閉包的作用域鏈決定了閉包只能包含外部函數中任何變量的最終值,舉個例子:
function createFunctions(){ var result = new Array(); for (var i=0; i < 10; i++){ result[i] = function(){ return i; }; } return result; } var result = createFunctions(); result[3](); // 10
上述例子中,我們在createFunctions函數中,通過for循環,創建了多個函數,并期望每一個都能返回創建它時的索引值,但結果發現,每一個函數都只能返回i的最終值(由于ECMAScript中沒有塊級作用域,因此i是createFunctions中的局部變量),之所以是這樣的結果,是因為每一個閉包能夠訪問到的i都是對局部變量i的引用,由于這種情況的存在,因此我們發現很多閉包都是這樣寫的:
function createFunctions(){ var result = new Array(); for (var i=0; i < 10; i++){ result[i] = function(num){ return function() { return num; } }(i); } return result; } var result = createFunctions(); result[3](); // 3
原理就是將動態的局部變量參數化,這樣每一個閉包都保存了該局部變量某個時刻的副本。
在閉包中使用thisthis是基于執行環境綁定的,如果是全局函數,那么this指window,如果是某個對象的函數,那么this指這個對象,而匿名函數的執行環境具有全局性,因此閉包中的this一般指window,比如:
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; }; } }; console.log(object.getNameFunc()()); //"The Window"
上述例子中,閉包是在全局環境中執行的,而我們知道,每個函數在執行時會基于執行環境自動獲得this,因此this指向了window。
上述例子中,如何使閉包可以訪問object呢,可以做如下修改:
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ var that = this; return function(){ return that.name; }; } }; object.getNameFunc()() // "My Object"內存泄漏
在之前的文章Javascript 變量、作用域和內存問題提到過IE在版本9之前,ECMAScript對象和DOM對象的GC機制不同,循環引用會導致DOM對象永遠不能被回收,學習完這一章節后才發現自己經常寫的一段代碼就存在這樣的問題!-_-,書中也提到了這個例子:
function assignHandler(){ var element = document.getElementById("someElement"); element.onclick = function(){ console.log(element.id); }; }
上面的代碼就創建了一個閉包作為element的事件處理程序,這里的循環引用體現在element的屬性onclick的值中存在對element的引用,即使退出assignHandler,element這個DOM對象也不會被引用計數機制GC,那么不在閉包中顯式地引用element,總可以了吧,就比如:
function assignHandler(){ var element = document.getElementById("someElement"); var id = element.id; element.onclick = function(){ console.log(id); }; }
答案是不行的,因為閉包中無論如何都是要保存一份對 assignHandler活動對象的引用的,自然包含element。
之前提到過,由于閉包中保存的只是函數活動對象的引用,那么閉包中能夠訪問的變量就具有動態性,上個例子中,閉包由于引用了assignHandler的活動對象,就引用了element,而element引用了一個DOM對象,那么,如果element不引用DOM對象,而是其他對象,比如null,那么element就可以被標記清楚機制GC。
function assignHandler(){ var element = document.getElementById("someElement"); var id = element.id; element.onclick = function(){ console.log(id); }; element = null; }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/94881.html
摘要:也許最好的理解是閉包總是在進入某個函數的時候被創建,而局部變量是被加入到這個閉包中。在函數內部的函數的內部聲明函數是可以的可以獲得不止一個層級的閉包。 前言 總括 :這篇文章使用有效的javascript代碼向程序員們解釋了閉包,大牛和功能型程序員請自行忽略。 譯者 :文章寫在2006年,可直到翻譯的21小時之前作者還在完善這篇文章,在Stackoverflow的How do Java...
摘要:但是閉包也不是什么復雜到不可理解的東西,簡而言之,閉包就是閉包就是函數的局部變量集合,只是這些局部變量在函數返回后會繼續存在。可惜的是,并沒有提供相關的成員和方法來訪問閉包中的局部變量。 (收藏自 技術狂) 前言:還是一篇入門文章。Javascript中有幾個非常重要的語言特性——對象、原型繼承、閉包。其中閉包 對于那些使用傳統靜態語言C/C++的程序員來說是一個新的語言特性。本文將...
摘要:當在中調用匿名函數時,它們用的都是同一個閉包,而且在這個閉包中使用了和的當前值的值為因為循環已經結束,的值為。最好將閉包當作是一個函數的入口創建的,而局部變量是被添加進這個閉包的。 閉包不是魔法 這篇文章使用一些簡單的代碼例子來解釋JavaScript閉包的概念,即使新手也可以輕松參透閉包的含義。 其實只要理解了核心概念,閉包并不是那么的難于理解。但是,網上充斥了太多學術性的文章,對于...
摘要:深入系列第八篇,介紹理論上的閉包和實踐上的閉包,以及從作用域鏈的角度解析經典的閉包題。定義對閉包的定義為閉包是指那些能夠訪問自由變量的函數。 JavaScript深入系列第八篇,介紹理論上的閉包和實踐上的閉包,以及從作用域鏈的角度解析經典的閉包題。 定義 MDN 對閉包的定義為: 閉包是指那些能夠訪問自由變量的函數。 那什么是自由變量呢? 自由變量是指在函數中使用的,但既不是函數參數也...
摘要:一言以蔽之,閉包,你就得掌握。當函數記住并訪問所在的詞法作用域,閉包就產生了。所以閉包才會得以實現。從技術上講,這就是閉包。執行后,他的內部作用域并不會消失,函數依然保持有作用域的閉包。 網上總結閉包的文章已經爛大街了,不敢說筆者這篇文章多么多么xxx,只是個人理解總結。各位看官瞅瞅就好,大神還希望多多指正。此篇文章總結與《JavaScript忍者秘籍》 《你不知道的JavaScri...
摘要:但是,必須強調,閉包是一個運行期概念。通過原型鏈可以實現繼承,而與閉包相關的就是作用域鏈。常理來說,一個函數執行完畢,其執行環境的作用域鏈會被銷毀。所以此時,的作用域鏈雖然銷毀了,但是其活動對象仍在內存中。 學習Javascript閉包(Closure)javascript的閉包JavaScript 閉包深入理解(closure)理解 Javascript 的閉包JavaScript ...
閱讀 3049·2021-11-22 15:29
閱讀 1729·2021-10-12 10:11
閱讀 1751·2021-09-04 16:45
閱讀 2229·2021-08-25 09:39
閱讀 2790·2021-08-18 10:20
閱讀 2511·2021-08-11 11:17
閱讀 447·2019-08-30 12:49
閱讀 3305·2019-08-30 12:49