摘要:閉包的注意事項(xiàng)通常,函數(shù)的作用域及其所有變量都會(huì)在函數(shù)執(zhí)行結(jié)束后被銷毀。但是,在創(chuàng)建了一個(gè)閉包以后,這個(gè)函數(shù)的作用域就會(huì)一直保存到閉包不存在為止。最后通過釋放了和對(duì)閉包的引用。從而使用閉包模塊化代碼,減少全局變量的污染。
JavaScript 閉包
什么是閉包(Closure)原文鏈接
簡(jiǎn)單講,閉包就是指有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù)。
MDN 上面這么說:閉包是一種特殊的對(duì)象。它由兩部分構(gòu)成:函數(shù),以及創(chuàng)建該函數(shù)的環(huán)境。環(huán)境由閉包創(chuàng)建時(shí)在作用域中的任何局部變量組成。
但是,網(wǎng)上找了好多資料,它們對(duì)閉包的定義也各有各樣,搞得我也不知道怎么去定義閉包了,所以干脆不去定義了,意會(huì)吧。
產(chǎn)生一個(gè)閉包道可道,非常道;名可名,非常名。
創(chuàng)建閉包最常見方式,就是在一個(gè)函數(shù)內(nèi)部創(chuàng)建另一個(gè)函數(shù)。下面例子中的 closure 就是一個(gè)閉包:
function func(){ var a = 1,b = 2; function closure(){ return a+b; } return closure; }
閉包的作用域鏈包含著它自己的作用域,以及包含它的函數(shù)的作用域和全局作用域。
閉包的注意事項(xiàng)通常,函數(shù)的作用域及其所有變量都會(huì)在函數(shù)執(zhí)行結(jié)束后被銷毀。但是,在創(chuàng)建了一個(gè)閉包以后,這個(gè)函數(shù)的作用域就會(huì)一直保存到閉包不存在為止。
function makeAdder(x) { return function(y) { return x + y; }; } var add5 = makeAdder(5); var add10 = makeAdder(10); console.log(add5(2)); // 7 console.log(add10(2)); // 12 // 釋放對(duì)閉包的引用 add5 = null; add10 = null;
add5 和 add10 都是閉包。它們共享相同的函數(shù)定義,但是保存了不同的環(huán)境。在 add5 的環(huán)境中,x 為 5。而在 add10 中,x 則為 10。最后通過 null 釋放了 add5 和 add10 對(duì)閉包的引用。
在javascript中,如果一個(gè)對(duì)象不再被引用,那么這個(gè)對(duì)象就會(huì)被垃圾回收機(jī)制回收;
如果兩個(gè)對(duì)象互相引用,而不再被第3者所引用,那么這兩個(gè)互相引用的對(duì)象也會(huì)被回收。
閉包只能取得包含函數(shù)中任何變量的最后一個(gè)值,這是因?yàn)殚]包所保存的是整個(gè)變量對(duì)象,而不是某個(gè)特殊的變量。
function test(){ var arr = []; for(var i = 0;i < 10;i++){ arr[i] = function(){ return i; }; } for(var a = 0;a < 10;a++){ console.log(arr[a]()); } } test(); // 連續(xù)打印 10 個(gè) 10
對(duì)于上面的情況,如果我們改變代碼如下:
function test(){ var arr = []; for(let i = 0;i < 10;i++){ // 僅在這里作出了改動(dòng) arr[i] = function(){ return i; }; } for(var a = 0;a < 10;a++){ console.log(arr[a]()); } } test(); // 打印 0 到 9
對(duì)于上面兩種代碼的解釋,請(qǐng)看我在 segmentfault 上面的提問:鏈接
閉包中的 this 對(duì)象
var name = "The Window"; var obj = { name: "My Object", getName: function(){ return function(){ return this.name; }; } }; console.log(obj.getName()()); // The Window
obj.getName()()實(shí)際上是在全局作用域中調(diào)用了匿名函數(shù),this指向了window。這里要理解函數(shù)名與函數(shù)功能(或者稱函數(shù)值)是分割開的,不要認(rèn)為函數(shù)在哪里,其內(nèi)部的this就指向哪里。匿名函數(shù)的執(zhí)行環(huán)境具有全局性,因此其 this 對(duì)象通常指向 window。
var name = "The Window"; var obj = { name: "My Object", getName: function(){ var that = this; return function(){ return that.name; }; } }; console.log(obj.getName()()); // My Object閉包的應(yīng)用
應(yīng)用閉包的主要場(chǎng)合是:設(shè)計(jì)私有的方法和變量。
任何在函數(shù)中定義的變量,都可以認(rèn)為是私有變量,因?yàn)椴荒茉诤瘮?shù)外部訪問這些變量。私有變量包括函數(shù)的參數(shù)、局部變量和函數(shù)內(nèi)定義的其他函數(shù)。
把有權(quán)訪問私有變量的公有方法稱為特權(quán)方法(privileged method)。
function Animal(){ // 私有變量 var series = "哺乳動(dòng)物"; function run(){ console.log("Run!!!"); } // 特權(quán)方法 this.getSeries = function(){ return series; }; }
模塊模式(The Module Pattern):為單例創(chuàng)建私有變量和方法。
單例(singleton):指的是只有一個(gè)實(shí)例的對(duì)象。JavaScript 一般以對(duì)象字面量的方式來創(chuàng)建一個(gè)單例對(duì)象。
var singleton = { name: "percy", speak:function(){ console.log("speaking!!!"); }, getName: function(){ return this.name; } };
上面是普通模式創(chuàng)建的單例,下面使用模塊模式創(chuàng)建單例:
var singleton = (function(){ // 私有變量 var age = 22; var speak = function(){ console.log("speaking!!!"); }; // 特權(quán)(或公有)屬性和方法 return { name: "percy", getAge: function(){ return age; } }; })();
匿名函數(shù)最大的用途是創(chuàng)建閉包,并且還可以構(gòu)建命名空間,以減少全局變量的使用。從而使用閉包模塊化代碼,減少全局變量的污染。
var objEvent = objEvent || {}; (function(){ var addEvent = function(){ // some code }; function removeEvent(){ // some code } objEvent.addEvent = addEvent; objEvent.removeEvent = removeEvent; })();
在這段代碼中函數(shù) addEvent 和 removeEvent 都是局部變量,但我們可以通過全局變量 objEvent 使用它,這就大大減少了全局變量的使用,增強(qiáng)了網(wǎng)頁的安全性。
一個(gè)閉包計(jì)數(shù)器
var countNumber = (function(){ var num = 0; return function(){ return ++num; }; })();閉包的缺陷
閉包的缺點(diǎn)就是常駐內(nèi)存會(huì)增大內(nèi)存使用量,并且使用不當(dāng)很容易造成內(nèi)存泄露。
如果不是因?yàn)槟承┨厥馊蝿?wù)而需要閉包,在沒有必要的情況下,在其它函數(shù)中創(chuàng)建函數(shù)是不明智的,因?yàn)殚]包對(duì)腳本性能具有負(fù)面影響,包括處理速度和內(nèi)存消耗。
最后再來一些有關(guān)閉包的面試題下面代碼中,標(biāo)記 ? 的地方輸出分別是什么?
function fun(n,o){ console.log(o); return { fun: function(m){ return fun(m,n); } }; } var a = fun(0); // ? a.fun(1); // ? a.fun(2); // ? a.fun(3); // ? var b = fun(0).fun(1).fun(2).fun(3); // ? var c = fun(0).fun(1); // ? c.fun(2); // ? c.fun(3); // ?
參考資料undefined
0
0
0
undefined, 0, 1, 2
undefined, 0
1
1
【書】《JavaScript 高級(jí)程序設(shè)計(jì)(第三版)》
【文章】學(xué)習(xí)Javascript閉包(Closure)
【文章】【JavaScript】【函數(shù)】閉包閉包!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/90947.html
摘要:也許最好的理解是閉包總是在進(jìn)入某個(gè)函數(shù)的時(shí)候被創(chuàng)建,而局部變量是被加入到這個(gè)閉包中。在函數(shù)內(nèi)部的函數(shù)的內(nèi)部聲明函數(shù)是可以的可以獲得不止一個(gè)層級(jí)的閉包。 前言 總括 :這篇文章使用有效的javascript代碼向程序員們解釋了閉包,大牛和功能型程序員請(qǐng)自行忽略。 譯者 :文章寫在2006年,可直到翻譯的21小時(shí)之前作者還在完善這篇文章,在Stackoverflow的How do Java...
摘要:但是閉包也不是什么復(fù)雜到不可理解的東西,簡(jiǎn)而言之,閉包就是閉包就是函數(shù)的局部變量集合,只是這些局部變量在函數(shù)返回后會(huì)繼續(xù)存在。可惜的是,并沒有提供相關(guān)的成員和方法來訪問閉包中的局部變量。 (收藏自 技術(shù)狂) 前言:還是一篇入門文章。Javascript中有幾個(gè)非常重要的語言特性——對(duì)象、原型繼承、閉包。其中閉包 對(duì)于那些使用傳統(tǒng)靜態(tài)語言C/C++的程序員來說是一個(gè)新的語言特性。本文將...
摘要:當(dāng)在中調(diào)用匿名函數(shù)時(shí),它們用的都是同一個(gè)閉包,而且在這個(gè)閉包中使用了和的當(dāng)前值的值為因?yàn)檠h(huán)已經(jīng)結(jié)束,的值為。最好將閉包當(dāng)作是一個(gè)函數(shù)的入口創(chuàng)建的,而局部變量是被添加進(jìn)這個(gè)閉包的。 閉包不是魔法 這篇文章使用一些簡(jiǎn)單的代碼例子來解釋JavaScript閉包的概念,即使新手也可以輕松參透閉包的含義。 其實(shí)只要理解了核心概念,閉包并不是那么的難于理解。但是,網(wǎng)上充斥了太多學(xué)術(shù)性的文章,對(duì)于...
摘要:深入系列第八篇,介紹理論上的閉包和實(shí)踐上的閉包,以及從作用域鏈的角度解析經(jīng)典的閉包題。定義對(duì)閉包的定義為閉包是指那些能夠訪問自由變量的函數(shù)。 JavaScript深入系列第八篇,介紹理論上的閉包和實(shí)踐上的閉包,以及從作用域鏈的角度解析經(jīng)典的閉包題。 定義 MDN 對(duì)閉包的定義為: 閉包是指那些能夠訪問自由變量的函數(shù)。 那什么是自由變量呢? 自由變量是指在函數(shù)中使用的,但既不是函數(shù)參數(shù)也...
摘要:一言以蔽之,閉包,你就得掌握。當(dāng)函數(shù)記住并訪問所在的詞法作用域,閉包就產(chǎn)生了。所以閉包才會(huì)得以實(shí)現(xiàn)。從技術(shù)上講,這就是閉包。執(zhí)行后,他的內(nèi)部作用域并不會(huì)消失,函數(shù)依然保持有作用域的閉包。 網(wǎng)上總結(jié)閉包的文章已經(jīng)爛大街了,不敢說筆者這篇文章多么多么xxx,只是個(gè)人理解總結(jié)。各位看官瞅瞅就好,大神還希望多多指正。此篇文章總結(jié)與《JavaScript忍者秘籍》 《你不知道的JavaScri...
摘要:但是,必須強(qiáng)調(diào),閉包是一個(gè)運(yùn)行期概念。通過原型鏈可以實(shí)現(xiàn)繼承,而與閉包相關(guān)的就是作用域鏈。常理來說,一個(gè)函數(shù)執(zhí)行完畢,其執(zhí)行環(huán)境的作用域鏈會(huì)被銷毀。所以此時(shí),的作用域鏈雖然銷毀了,但是其活動(dòng)對(duì)象仍在內(nèi)存中。 學(xué)習(xí)Javascript閉包(Closure)javascript的閉包JavaScript 閉包深入理解(closure)理解 Javascript 的閉包JavaScript ...
閱讀 3262·2021-11-11 11:00
閱讀 2582·2019-08-29 11:23
閱讀 1463·2019-08-29 10:58
閱讀 2347·2019-08-29 10:58
閱讀 2966·2019-08-23 18:26
閱讀 2523·2019-08-23 18:18
閱讀 2053·2019-08-23 16:53
閱讀 3427·2019-08-23 13:13