閉包是什么、用處如何

大家好,我是IT修真院成都分院第6期的學(xué)員,一枚正直純潔善良的前端程序員。今天給大家?guī)淼氖情]包是什么,用處如何?

1.背景介紹

閉包(closure)是JS中一個較難理解的一個概念,JS函數(shù)的執(zhí)行依賴于變量作用域,函數(shù)對象的內(nèi)部狀態(tài)包含函數(shù)自身的邏輯,還必須引用當(dāng)前的作用域鏈。函數(shù)對象可以相互關(guān)聯(lián)起來,函數(shù)體內(nèi)部的變量可以保存在函數(shù)作用域內(nèi),具有這種特性的函數(shù)稱為閉包。從這個概念上講,所有的函數(shù)都是閉包。

2.知識剖析

閉包可以用在許多地方。它的最大用處有兩個:

1.可以讀取函數(shù)內(nèi)部的變量

2.讓這些變量的值始終保存在內(nèi)存中

讀取函數(shù)內(nèi)部的變量的例子:

/*使用閉包讀取函數(shù)內(nèi)部的變量*/

function f1(){

n = 999;

function f2(){

alert(n);

}

return f2;

}

var result = f1();

result(); //999

在上面的代碼中,函數(shù)f2就被包括在函數(shù)f1內(nèi)部,這時f1內(nèi)部的所有局部變量,對f2都是可見的。但是反過來就不行,f2內(nèi)部的局部變量,對f1就是不可見的。這就是Javascript語言特有的"鏈式作用域"結(jié)構(gòu)(chain scope),子對象會一級一級地向上尋找所有父對象的變量。所以,父對象的所有變量,對子對象都是可見的,反之則不成立。既然f2可以讀取f1中的局部變量,那么只要把f2作為返回值,我們不就可以在f1外部讀取它的內(nèi)部變量了嗎?

變量的值始終保存在內(nèi)存的例子:

/*使用閉包讓函數(shù)內(nèi)部的變量儲存在內(nèi)存中*/

function f1(){

n = 999;

nAdd = function(){

n+=1;

};

function f2(){

alert(n);

}

return f2;

}

var result = f1();

result();//999

nAdd();

result();//1000

在這段代碼中,result實際上就是閉包f2函數(shù)。它一共運行了兩次,第一次的值是999,第二次的值是1000。這證明了,函數(shù)f1中的局部變量n一直保存在內(nèi)存中,并沒有在f1調(diào)用后被自動清除。因為f1是f2的父函數(shù),而f2被賦給了一個全局變量,這導(dǎo)致f2始終在內(nèi)存中,而f2的存在依賴于f1,因此f1也始終在內(nèi)存中,不會在調(diào)用結(jié)束后,被垃圾回收機制(garbage collection)回收。這段代碼中另一個值得注意的地方,就是"nAdd=function(){n+=1}"這一行,首先在nAdd前面沒有使用var關(guān)鍵字,因此nAdd是一個全局變量,而不是局部變量。其次,nAdd的值是一個匿名函數(shù)(anonymous function),而這個匿名函數(shù)本身也是一個閉包,所以nAdd相當(dāng)于是一個setter,可以在函數(shù)外部對函數(shù)內(nèi)部的局部變量進行操作。

3.常見問題

window.onload = function(){

var el = document.getElementById("id");

el.onclick = function(){

alert(el.id);

}

}

這段代碼會造成內(nèi)存泄漏,為什么?

4.解決方案

內(nèi)存泄漏的原因:執(zhí)行這段代碼的時候,將匿名函數(shù)對象賦值給el的onclick屬性;然后匿名函數(shù)內(nèi)部又引用了el對象,存在循環(huán)引用,所以不能被垃圾回收機制回收;

修改后:

window.onload = function(){

var el = document.getElementById("id");

var id = el.id; //解除循環(huán)引用

el.onclick = function(){

alert(id);

}

el = null; // 將閉包引用的外部函數(shù)中活動對象清除

}

5.編碼實戰(zhàn)

在函數(shù)執(zhí)行過程中,為讀取和寫入變量的值,就需要在作用域鏈中查找變量

function compare(value1, value2){

if (value1 < value2){

return -1;

} else if (value1 > value2){

return 1;

} else {

return 0;

}

}

var result = compare(5, 10);

以上代碼先定義了compare()函數(shù),然后又在全局作用域中調(diào)用了它。

6.擴展思考

閉包有什么優(yōu)缺點,何時使用?

7.參考文獻

參考一:阮一峰的網(wǎng)絡(luò)日志:學(xué)習(xí)Javascript閉包

參考二:知乎專欄:JS中的閉包是什么?

參考三:segmentfault:JS進階之閉包

8.更多討論

討論一:在閉包中的this指向問題?

this是一個關(guān)鍵字而不是變量,每個函數(shù)調(diào)用都包含一個this值,如果閉包在外部函數(shù)里是無法訪問this的,除非在外部函數(shù)將this轉(zhuǎn)存為一個變量

討論二:閉包會產(chǎn)生內(nèi)存泄漏的原因?

閉包保存在內(nèi)存里的是我們需要的變量,不屬于內(nèi)存泄漏。IE在我們使用完閉包之后,依然回收不了閉包里面引用的變量。

課后

Q1:簡述閉包是什么

A1:外部函數(shù)訪問函數(shù)內(nèi)部變量

Q2:怎么樣避免被回收

A2:將函數(shù)賦值給變量。

Q3:內(nèi)存泄漏的原因

A3:閉包保存在內(nèi)存里的是我們需要的變量,不屬于內(nèi)存泄漏。IE在我們使用完閉包之后,依然回收不了閉包里面引用的變量。


閉包是什么?用處如何?_騰訊視頻


PPT鏈接:PPT鏈接

視頻鏈接:視頻鏈接

今天的分享就到這里啦,歡迎大家點贊、轉(zhuǎn)發(fā)、留言、拍磚~

技能樹.IT修真院

“我們相信人人都可以成為一個工程師,現(xiàn)在開始,找個師兄,帶你入門,掌控自己學(xué)習(xí)的節(jié)奏,學(xué)習(xí)的路上不再迷?!?。

這里是技能樹.IT修真院,成千上萬的師兄在這里找到了自己的學(xué)習(xí)路線,學(xué)習(xí)透明化,成長可見化,師兄1對1免費指導(dǎo)。快來與我一起學(xué)習(xí)吧?!

歡迎進入修真之旅!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 大家好,我是IT修真院北京分院25期的學(xué)員,一枚正直純潔善良的web前端程序員 今天給大家分享一下,修真院官網(wǎng)js...
    be684ac78b0c閱讀 351評論 0 0
  • 大家好,我是IT修真院北京分院22期的學(xué)員,一枚正直純潔善良的web前端程序員 今天給大家分享一下,修真院官網(wǎng)js...
    古碑先生閱讀 383評論 0 0
  • 大家好,我是IT修真院上海分院第01期學(xué)員,一枚正直善良的web程序員。 今天給大家分享一下,修真院官網(wǎng) CSS任...
    愛貓先森閱讀 11,954評論 0 3
  • 大家好,我是IT修真院深圳分院第01期學(xué)員,一枚正直善良的web程序員。 今天給大家分享一下,修真院官網(wǎng) JS任務(wù)...
    長天_閱讀 455評論 0 2
  • 大家好,我是IT修真院成都分院第8期的學(xué)員,一枚正直純潔善良的WEB前端程序員。今天給大家分享一下閉包是什么,用處...
    備用的昵稱閱讀 272評論 0 0

友情鏈接更多精彩內(nèi)容