摘要:什么是閉包紅寶書上給出的定義是閉包是指有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù),看到另外一個(gè)理解是函數(shù)和函數(shù)內(nèi)部能訪問到的變量或者環(huán)境的總合,就是一個(gè)閉包。閉包用于創(chuàng)建單例所謂單例,就是只有一個(gè)實(shí)例的對(duì)象。它使用立即執(zhí)行函數(shù)和閉包來(lái)達(dá)到目的。
面試必問題目,但總覺得理解得不深入,索性寫一篇文章慢慢梳理吧。
什么是閉包紅寶書上給出的定義是:閉包是指有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù),看到另外一個(gè)理解是:函數(shù)和函數(shù)內(nèi)部能訪問到的變量(或者環(huán)境)的總合,就是一個(gè)閉包。創(chuàng)建一個(gè)閉包最常見的方式就是在一個(gè)函數(shù)內(nèi)部創(chuàng)建另一個(gè)函數(shù)。下面寫一個(gè)例子:
function f1() { var a = 1; function closure() { console.log(++a); } return closure; }
上面例子中,f1 內(nèi)部的匿名函數(shù)以及它能夠訪問到的外部函數(shù)的變量 a 合在一起,就形成了一個(gè)閉包。使用 return 將閉包返回的目的是讓它可以被外部訪問。下面看看它怎么使用:
var f2 = f1(); // 執(zhí)行外部函數(shù),返回閉包 f2(); // 2 f2(); // 3 f2(); // 4
第一句執(zhí)行函數(shù) f1() 后,閉包被返回并賦值給了一個(gè)全局變量 f2,以后每次調(diào)用 f2(),變量 a 的值就會(huì)加 1。通常函數(shù)執(zhí)行完畢后,其作用域鏈和活動(dòng)對(duì)象都會(huì)被銷毀,為什么這里 a 并沒有被銷毀并且每次執(zhí)行 f2() 還會(huì)被遞增?原因是閉包有權(quán)訪問外部函數(shù)的變量,進(jìn)一步說,閉包的作用域鏈會(huì)引用外部函數(shù)的活動(dòng)對(duì)象,所以 f2() 在執(zhí)行時(shí),其作用域鏈實(shí)際上是:
自身的活動(dòng)對(duì)象;
f1() 的活動(dòng)對(duì)象;
全局變量對(duì)象。
所以 f1() 執(zhí)行完后,其執(zhí)行環(huán)境的作用域鏈會(huì)被銷毀,但活動(dòng)對(duì)象仍然會(huì)留在內(nèi)存中,因?yàn)殚]包作用域鏈在引用這個(gè)活動(dòng)對(duì)象(說白了就是閉包還需要使用外層函數(shù)的變量,不允許它們被銷毀),直到閉包被銷毀后,f1() 的活動(dòng)對(duì)象才會(huì)被銷毀。
上面例子中,是將返回的閉包賦值給了一個(gè)全局變量 f2,var f2 = f1();,f2 是不會(huì)被銷毀的,每次執(zhí)行完 f2(),閉包的作用域鏈不會(huì)被銷毀,所以就會(huì)出現(xiàn)每次執(zhí)行 f2(),a 遞增。
但是換一種閉包的調(diào)用方式,情況會(huì)不同:
f1()(); // 2 f1()(); // 2
因?yàn)闆]有把閉包賦值給一個(gè)全局變量,閉包執(zhí)行完后,其執(zhí)行域鏈與活動(dòng)對(duì)象都銷毀了。
閉包的作用 創(chuàng)建用于訪問私有變量的公有方法其實(shí)構(gòu)造函數(shù)中定義的實(shí)例方法,就是閉包:
function Person(){ var name = "Leon"; function sayHi() { alert("Hi!"); } this.publicMethod = function() { alert(name); return sayHi(); } }
構(gòu)造函數(shù) Person 中定義實(shí)例方法 publicMethod() 就是一個(gè)閉包,它可以訪問外部函數(shù)的變量 name 和 函數(shù) sayHi(),為什么要這么做呢?因?yàn)槲覀兿朐跇?gòu)造函數(shù)中定義一些私有變量,讓外部不能直接訪問,只能通過定義好的公有方法訪問,從而達(dá)到保護(hù)變量,收斂外部權(quán)限的目的。
而在普通函數(shù)中,把閉包 return 出去供外部使用,其實(shí)目的也就是:讓函數(shù)內(nèi)部的變量始終保持在內(nèi)存中,同時(shí)保護(hù)這些變量,讓它們不能被直接訪問。
function person(){ var name = "Leon"; function sayHi() { alert("Hi!"); } function publicMethod() { alert(name); return sayHi(); } return publicMethod; }閉包用于創(chuàng)建單例
所謂單例,就是只有一個(gè)實(shí)例的對(duì)象。單例模式的好處在于:
保證一個(gè)類只有一個(gè)實(shí)例,避免了一個(gè)在全局范圍內(nèi)使用的實(shí)例頻繁創(chuàng)建與銷毀。
比如網(wǎng)頁(yè)中的彈窗,點(diǎn)擊 a 按鈕彈出,點(diǎn)擊 b 按鈕隱藏,如果彈窗每一次彈出都需要新建一個(gè)對(duì)象,將會(huì)造成性能的浪費(fèi),更好的辦法就是只實(shí)例化一個(gè)對(duì)象,一直使用。
劃分了命名空間,避免了與全局命名空間的沖突。
比如在一個(gè)單例中可以定義很多方法,通過單例.方法來(lái)使用,避免了在全局環(huán)境中定義函數(shù),造成函數(shù)名沖突。
下面逐步介紹下單例的創(chuàng)建方式,后兩種方式將用到閉包。
1. 對(duì)象字面量創(chuàng)建單例var singleton = { attr1: 1, attr2: 2, method: function () { return this.attr1 + this.attr2; } } var s1 = singleton; var s2 = singleton; console.log(s1 == s2) // true
上面用字面量形式創(chuàng)建了一個(gè)單例,可以看到 s1 和 s2 是等同的。這種方式的問題在于外部可以直接訪問單例的內(nèi)部變量并加以修改,如果想讓單例擁有私有變量,就需要使用模塊模式,模塊模式就是用了閉包。
2. 模塊模式JS 中的模塊模式的作用是:為單例添加私有變量和公有方法。它使用立即執(zhí)行函數(shù)和閉包來(lái)達(dá)到目的。
var singleton = (function(){ // 創(chuàng)建私有變量 var privateNum = 1; // 創(chuàng)建私有函數(shù) function privateFunc(){ console.log(++privateNum); } // 返回一個(gè)對(duì)象包含公有方法 return { publicMethod: function(){ console.log(privateNum) return privateFunc() } }; })(); singleton.publicMethod(); // 1 // 2
這里首先定義了一個(gè)立即執(zhí)行函數(shù),它返回一個(gè)對(duì)象,該對(duì)象中有一個(gè)閉包 publicMethod(), 它可以訪問外部函數(shù)的私有變量。從而這個(gè)被返回的對(duì)象就成為了單例的公共接口,外部可以通過它的公有方法訪問私有變量而無(wú)權(quán)直接修改。總結(jié)一下就是兩點(diǎn):
立即執(zhí)行函數(shù)可以創(chuàng)建一個(gè)塊級(jí)作用域, 避免在全局環(huán)境中添加變量。
閉包可以訪問外層函數(shù)中的變量。
3. 構(gòu)造函數(shù)+閉包上面提到的對(duì)象字面是用來(lái)創(chuàng)建單例的方法之一,既然單例只能被實(shí)例化一次,不難想到,在使用構(gòu)造函數(shù)新建實(shí)例時(shí),先判斷實(shí)例是否已被新建,未被新建則新建實(shí)例,否則直接返回已被新建的實(shí)例。
var Singleton = function(name){ this.name = name; }; // 獲取實(shí)例對(duì)象 var getInstance = (function() { var instance = null; return function(name) { if(!instance) { instance = new Singleton(name); } return instance; } })(); var a = getInstance("1"); console.log(a); // {name: "1"} var b = getInstance("2"); console.log(b); // {name: "1"}
這里將構(gòu)造函數(shù)和實(shí)例化過程進(jìn)行了分離, getInstance()中存在一個(gè)閉包,它可以訪問到外部變量 instance,第一次 instance = null,則通過 new Singleton(name) 新建實(shí)例,并將這個(gè)實(shí)例保存在instance 中,之后再想新建實(shí)例,因?yàn)殚]包訪問到的instance已經(jīng)有值了,就會(huì)直接返回之前實(shí)例化的對(duì)象。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/108459.html
摘要:第二梯隊(duì)理解有了第一梯隊(duì)的認(rèn)識(shí),我們慢慢修正大腦中對(duì)閉包的認(rèn)識(shí)。理解這句話就可以很好的與閉包這兩個(gè)字關(guān)聯(lián)起來(lái)理解閉包這個(gè)概念了。總結(jié)第二梯隊(duì)理解閉包是一個(gè)有特定功能的函數(shù)。第四梯隊(duì)理解閉包通過訪問外部變量,一個(gè)閉包可以維持這些變量。 閉包 閉包的概念困惑了我很久,記得當(dāng)時(shí)我面試的時(shí)候最后一面有一個(gè)問題就是問題關(guān)于閉包的問題,然而到現(xiàn)在已經(jīng)完全不記得當(dāng)時(shí)的題目是啥了,但仍然能夠回憶起當(dāng)時(shí)...
摘要:如何在初學(xué)就理解閉包你需要接著讀下去。這樣定義閉包是函數(shù)和聲明該函數(shù)的詞法環(huán)境的組合。小結(jié)閉包在中隨處可見。閉包是中的精華部分,理解它需要具備一定的作用域執(zhí)行棧的知識(shí)。 這是本系列的第 4 篇文章。 作為 JS 初學(xué)者,第一次接觸閉包的概念是因?yàn)閷懗隽祟愃葡旅娴拇a: for (var i = 0; i < helpText.length; i++) { var item = he...
摘要:當(dāng)初看這個(gè)解釋有點(diǎn)懵逼,理解成閉包就是函數(shù)中的函數(shù)了。里的閉包最近不滿足于只干前端的活,開始用起了。里的閉包最近在學(xué)習(xí)語(yǔ)言,讓我們來(lái)看一下語(yǔ)言里的閉包。在中,閉包特指將函數(shù)作為值返回的情況,被返回的函數(shù)引用了生成它的母函數(shù)中的變量。 本人開始接觸編程是從js開始的,當(dāng)時(shí)網(wǎng)上很多人說閉包是難點(diǎn),各種地方對(duì)閉包的解釋也是千奇百怪。如今開始接觸js以外的各種編程語(yǔ)言,發(fā)現(xiàn)不光是js,php、...
摘要:當(dāng)初看這個(gè)解釋有點(diǎn)懵逼,理解成閉包就是函數(shù)中的函數(shù)了。里的閉包最近不滿足于只干前端的活,開始用起了。里的閉包最近在學(xué)習(xí)語(yǔ)言,讓我們來(lái)看一下語(yǔ)言里的閉包。在中,閉包特指將函數(shù)作為值返回的情況,被返回的函數(shù)引用了生成它的母函數(shù)中的變量。 本人開始接觸編程是從js開始的,當(dāng)時(shí)網(wǎng)上很多人說閉包是難點(diǎn),各種地方對(duì)閉包的解釋也是千奇百怪。如今開始接觸js以外的各種編程語(yǔ)言,發(fā)現(xiàn)不光是js,php、...
摘要:閉包在我理解是一種比較抽象的東西。所以我寫了一篇博文來(lái)方便自己理解閉包。那么現(xiàn)在我們可以解釋一下閉包的第一個(gè)定義在計(jì)算機(jī)科學(xué)中,閉包是引用了自由變量的函數(shù)。循環(huán)中創(chuàng)建閉包在我們使用的關(guān)鍵字之前,閉包的一個(gè)常見問題就出現(xiàn)在循環(huán)中創(chuàng)建閉包。 零. 前言 從我開始接觸前端時(shí)就聽說過閉包,但是一直不理解閉包究竟是什么。上網(wǎng)看了各種博客,大家對(duì)閉包的說法不一。閉包在我理解是一種比較抽象的東西。所...
摘要:但是閉包也不是什么復(fù)雜到不可理解的東西,簡(jiǎn)而言之,閉包就是閉包就是函數(shù)的局部變量集合,只是這些局部變量在函數(shù)返回后會(huì)繼續(xù)存在??上У氖?,并沒有提供相關(guān)的成員和方法來(lái)訪問閉包中的局部變量。 (收藏自 技術(shù)狂) 前言:還是一篇入門文章。Javascript中有幾個(gè)非常重要的語(yǔ)言特性——對(duì)象、原型繼承、閉包。其中閉包 對(duì)于那些使用傳統(tǒng)靜態(tài)語(yǔ)言C/C++的程序員來(lái)說是一個(gè)新的語(yǔ)言特性。本文將...
閱讀 3739·2021-11-24 09:39
閱讀 1894·2021-11-16 11:45
閱讀 626·2021-11-16 11:45
閱讀 1049·2021-10-11 10:58
閱讀 2493·2021-09-09 11:51
閱讀 1949·2019-08-30 15:54
閱讀 703·2019-08-29 13:13
閱讀 3478·2019-08-26 12:18