閉包是什么赔硫?用處如何?
it修真院小課堂
目錄
1.背景介紹
2.知識剖析
3.常見問題
4.解決方案
5.編碼實(shí)戰(zhàn)
6.擴(kuò)展思考
7.參考文獻(xiàn)
8.更多討論
1.背景介紹
閉包(closure)是Javascript語言的一個(gè)難點(diǎn)倒谷,也是它的特色玫氢,很多高級應(yīng)用都要依靠閉包實(shí)現(xiàn)。閉包是「函數(shù)」和「函數(shù)內(nèi)部能訪問到的變量」(也叫環(huán)境)的總和讲仰。
2.知識剖析
閉包可以用在許多地方慕趴。它的最大用處有兩個(gè):
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)部,這時(shí)f1內(nèi)部的所有局部變量冕房,對f2都是可見的躏啰。但是反過來就不行,f2內(nèi)部的局部變量耙册,對f1就是不可見的给僵。這就是Javascript語言特有的"鏈?zhǔn)阶饔糜?結(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實(shí)際上就是閉包f2函數(shù)。它一共運(yùn)行了兩次蹋宦,第一次的值是999披粟,第二次的值是1000。這證明了冷冗,函數(shù)f1中的局部變量n一直保存在內(nèi)存中守屉,并沒有在f1調(diào)用后被自動清除。因?yàn)閒1是f2的父函數(shù)蒿辙,而f2被賦給了一個(gè)全局變量拇泛,這導(dǎo)致f2始終在內(nèi)存中,而f2的存在依賴于f1思灌,因此f1也始終在內(nèi)存中俺叭,不會在調(diào)用結(jié)束后,被垃圾回收機(jī)制(garbage collection)回收泰偿。這段代碼中另一個(gè)值得注意的地方熄守,就是"nAdd=function(){n+=1}"這一行,首先在nAdd前面沒有使用var關(guān)鍵字耗跛,因此nAdd是一個(gè)全局變量裕照,而不是局部變量。其次调塌,nAdd的值是一個(gè)匿名函數(shù)(anonymous function)晋南,而這個(gè)匿名函數(shù)本身也是一個(gè)閉包,所以nAdd相當(dāng)于是一個(gè)setter羔砾,可以在函數(shù)外部對函數(shù)內(nèi)部的局部變量進(jìn)行操作负间。
3.常見問題
window.onload = function(){
var el = document.getElementById("id");
el.onclick = function(){
alert(el.id);
}
}
這段代碼為什么會造成內(nèi)存泄露紊扬?
4.解決方案
內(nèi)存泄漏的原因:執(zhí)行這段代碼的時(shí)候,將匿名函數(shù)對象賦值給el的onclick屬性唉擂;然后匿名函數(shù)內(nèi)部又引用了el對象,存在循環(huán)引用檀葛,所以不能被垃圾回收機(jī)制回收玩祟;
修改后:
window.onload = function(){
var el = document.getElementById("id");
? ? ? ? ? ? ? ? var id = el.id; //解除循環(huán)引用
? ? ? ? ? ? ? ? el.onclick = function(){
alert(id);
}
? ? ? ? ? ? ? ? el = null; // 將閉包引用的外部函數(shù)中活動對象清除
? ? ? ? ? ? ? ? }
5.編碼實(shí)戰(zhàn)
點(diǎn)擊按鈕會彈出相應(yīng)的數(shù)字0、1屿聋、2空扎、3、4
function init) {
var pAry = document.getElementsByTagName("button");
for( var i=0; i< pAry.length; i++ ) {
(function(arg){
pAry[i].onclick = function() {
alert(arg);
};
? ? ? ? ? ? ? ? })(i);//調(diào)用時(shí)參數(shù)
? ? ? ? ? ? ? ? }
}
思路:加一層閉包润讥,i以局部變量形式傳遞給內(nèi)存函數(shù)转锈,在js任務(wù)4中的殺人游戲選中的身份死亡有用到。
6.擴(kuò)展思考
在閉包中的this指向問題
7.參考文獻(xiàn)
8.更多討論
垃圾回收機(jī)制(garbage collection)以及匿名函數(shù)
感謝觀看
今天的分享就到這里啦楚殿,歡迎大家點(diǎn)贊撮慨、轉(zhuǎn)發(fā)、留言脆粥、拍磚~
技能樹.IT修真院???
? “我們相信人人都可以成為一個(gè)工程師砌溺,現(xiàn)在開始,找個(gè)師兄变隔,帶你入門规伐,掌控自己學(xué)習(xí)的節(jié)奏,學(xué)習(xí)的路上不再迷孟辉担”猖闪。
? ?這里是技能樹.IT修真院,成千上萬的師兄在這里找到了自己的學(xué)習(xí)路線肌厨,學(xué)習(xí)透明化培慌,成長可見化,師兄1對1免費(fèi)指導(dǎo)柑爸。
? ?快來與我一起學(xué)習(xí)吧~http://www.jnshu.com/login/1/21109035