當(dāng)前位置:
首頁(yè) >
前端技术
> javascript
>内容正文
javascript
【初窥javascript奥秘之闭包】叶大侠病都好了,求不踩了:)
生活随笔
收集整理的這篇文章主要介紹了
【初窥javascript奥秘之闭包】叶大侠病都好了,求不踩了:)
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
前言
咳咳,葉大俠病了,昨天晚上回家時(shí)候在車(chē)上就不舒服,果然回來(lái)就掛了,本來(lái)還想今天接著上班撐下去的。但是昨天又看到一個(gè)IT巨子掛了,所以果斷請(qǐng)了一個(gè)假!!!
但是早上7.00左右就迷迷糊糊的醒了,于是我在想我是不是該“身殘志堅(jiān)”一番。。。。
咳咳,以上玩笑,我們最近一起學(xué)習(xí)了很多CSS的東西,相信大家的CSS水平必定提高了吧???所以我們接下來(lái)一段時(shí)間來(lái)看看javascript吧,今天我們一起來(lái)看看閉包這個(gè)家伙!
本文參考:
http://www.cnblogs.com/TomXu/
http://www.cnblogs.com/lhb25/archive/2011/09/06/javascript-scope-chain.html
http://www.cnblogs.com/frankfang/archive/2011/08/03/2125663.html
http://www.cnblogs.com/xiaotie/archive/2011/08/03/2126145.html
執(zhí)行上下文(execution context)
又是上下文。。。無(wú)論是曾經(jīng)學(xué)習(xí).net時(shí)候的httpcontext,還是最近學(xué)習(xí)的block formatting context,都是上下文!
我們可以感覺(jué)到上下文的存在,就如感覺(jué)得到空氣一樣,我們卻將它拿不出來(lái),于是我們來(lái)看看執(zhí)行上下文吧。
每次當(dāng)控制器轉(zhuǎn)到ecmascript可執(zhí)行代碼的時(shí)候,就會(huì)進(jìn)入一個(gè)執(zhí)行上下文。 活動(dòng)的執(zhí)行上下文組在邏輯上為一個(gè)堆棧,堆棧最底部一定是全局上下文(global context),頂部便是當(dāng)前上下文 這個(gè)句話(huà)是很有玄機(jī)的哦,比如我們?cè)谝粋€(gè)函數(shù)環(huán)境中,我們首先用的是當(dāng)前變量,若是沒(méi)有就在父級(jí)函數(shù)中找,最后就在window中找。
PS:我們?cè)趯?xiě)博客時(shí)候,中文沒(méi)有問(wèn)題,突然打一個(gè)字母上,你會(huì)發(fā)現(xiàn)整行都下移了1/2px,各位知道神馬原因么???:)
eval在執(zhí)行時(shí)候會(huì)產(chǎn)生一個(gè)調(diào)用上下文的東東(calling context),所以eval中定義的變量會(huì)影響函數(shù)環(huán)境中的變量。
作用域
閉包有作用域鏈有很多說(shuō)不清道不明的關(guān)系,所以我們還是先看看作用域吧。
任何語(yǔ)言都會(huì)有作用域的概念,作用域便是變量與函數(shù)可訪(fǎng)問(wèn)范圍,簡(jiǎn)稱(chēng)變量與函數(shù)的生命周期。 javascript中分為全局與局部?jī)煞N,直白點(diǎn)window與function
復(fù)制代碼 var name = '葉小釵'; function func() { var id = '刀狂劍癡'; function alertId() { alert(id); } alertId(); } alert(name);//葉小釵 alert(id);//錯(cuò)誤 func(); //刀狂劍癡 alertId();//錯(cuò)誤 復(fù)制代碼 此處name屬于window屬性便是全局的(有些瀏覽器自帶name屬性小心陷阱!)
func也是全局的,但是func這個(gè)作用域鏈包含了全局的,所以他可以訪(fǎng)問(wèn)外部的,但是外部不能訪(fǎng)問(wèn)進(jìn)來(lái)。
鏈子。。。
在js中什么都是對(duì)象,函數(shù)和其它對(duì)象一樣擁有很多屬性,其中一個(gè)比較特殊的屬性是:
[[scope]],scope翻譯過(guò)來(lái)就是作用域,該屬性包含了函數(shù)被創(chuàng)建的作用域中的對(duì)象的集合:
于是傳說(shuō)中的作用域鏈誕生了,他決定了哪些數(shù)據(jù)能被哪些函數(shù)訪(fǎng)問(wèn)。
當(dāng)一個(gè)函數(shù)創(chuàng)建后,他的作用域鏈會(huì)被創(chuàng)建此函數(shù)的作用域中可訪(fǎng)問(wèn)的數(shù)據(jù)對(duì)象填充:
function add (a, b) { var sum = a + b; return sum; } 在函數(shù)add創(chuàng)建時(shí),他的作用域鏈中會(huì)填入一個(gè)全局對(duì)象,我們可以想象為window被壓入了其[[scope]]
函數(shù)add的作用域在調(diào)用時(shí)會(huì)被用到,此時(shí)會(huì)創(chuàng)建一個(gè)“運(yùn)行時(shí)上下文(execution context)”的內(nèi)部對(duì)象, 他定義了函數(shù)執(zhí)行時(shí)的環(huán)境,每個(gè)運(yùn)行時(shí)上下文都有自己的作用域鏈,用于標(biāo)識(shí)符解析, 當(dāng)execution context創(chuàng)建時(shí),而他的作用域鏈初始化為當(dāng)前運(yùn)行函數(shù)的[[scope]]所包含的對(duì)象。 所有相關(guān)的東東會(huì)按照其在函數(shù)中出現(xiàn)的順序被復(fù)制到運(yùn)行時(shí)上下文的作用域鏈中,他們共同組成了“活動(dòng)對(duì)象(activation object)”,該對(duì)象就包含了函數(shù)的所有局部變量,參數(shù),以及this,然后會(huì)排在我們作用域堆棧的頂端,我們可以最先獲取,在運(yùn)行時(shí)上下文結(jié)束(函數(shù)執(zhí)行完畢)后,GC便會(huì)回收其空間。
在函數(shù)執(zhí)行過(guò)程中,遇到一個(gè)變量便會(huì)經(jīng)歷一次標(biāo)識(shí)符解析以決定從哪里獲取以及存儲(chǔ)數(shù)據(jù)。
這個(gè)過(guò)程首先從我們的“堆棧”頂端開(kāi)始搜索,也就是活動(dòng)對(duì)象的開(kāi)始,若是有該變量便獲取值,
若是沒(méi)有則向下,知道window為止,沒(méi)有就報(bào)錯(cuò)!
內(nèi)存溢出
是想我們的瀏覽器內(nèi)存若是搞滿(mǎn)了,自然會(huì)瀏覽器崩潰,這是我們閉包之中需要考慮到的東西,因?yàn)樗麜?huì)導(dǎo)致我們一些東西無(wú)法GC。
閉包,神奇的魔法
閉包是神奇的魔法,因?yàn)樗闪撕芏唷皦氖隆?#xff0c;達(dá)到了出人意料的結(jié)果。
所謂閉包,便是function嵌套function,內(nèi)部function可以訪(fǎng)問(wèn)外部的變量。 若是外部函數(shù)返回了內(nèi)部函數(shù),那么就閉了一個(gè)包 復(fù)制代碼 1 function a() { 2 ? ? var name = '葉小釵'; 3 ? ? function alertName() { 4 ? ? ? ? alert(name); 5 ? ? } 6 ? ? return alertName; 7 } 8? 9 var func = a(); 10 func();//葉小釵 復(fù)制代碼 這個(gè)家伙是個(gè)壞孩子,怎么說(shuō)呢,壞孩子招人疼啊!
我們看第9行,按我們之前的理解a執(zhí)行結(jié)束后,整個(gè)活動(dòng)對(duì)象是不是該被銷(xiāo)毀?是不是與a有關(guān)的東西都該GC呢?
確實(shí)是這樣的,但是我們這里就產(chǎn)生了一個(gè)閉包,阻止了其銷(xiāo)毀,因?yàn)樗锩娴淖兞勘挥玫搅恕?
這里的一個(gè)事實(shí)便是外部的func訪(fǎng)問(wèn)到了a內(nèi)部的變量!
一個(gè)經(jīng)典的例子:
復(fù)制代碼 1 function outer() { 2 ? ? var o = {}; 3 ? ? for (var i = 0; i < 10; i++) { 4 ? ? ? ? o[i] = function () { 5 ? ? ? ? ? ? alert(i); 6 ? ? ? ? } 7 ? ? } 8 ? ? return o; 9 } 10 var funcs = outer(); 11 for (var k in funcs) { 12 ? ? funcs[k](); 13 } 14 var s = ''; 復(fù)制代碼 我們來(lái)看這個(gè),大家應(yīng)該都比較熟悉了,我們知道他全部會(huì)打印10。
這是因?yàn)槲覀儗uter給予funcs時(shí)候,outer的任務(wù)就完成啦,他現(xiàn)在內(nèi)部的i便是10,我們現(xiàn)在再來(lái)調(diào)用函數(shù),所有的i自然是指向一個(gè)[[scope]],所以變量i就是10!!!
要怎么解決大家也一目了然:
復(fù)制代碼 1 function outer() { 2 ? ? var o = {}; 3 ? ? for (var i = 0; i < 10; i++) { 4 ? ? ? ? o[i] = (function (i) { 5 ? ? ? ? ? ? alert(i); 6 ? ? ? ? })(i) 7 ? ? } 8 ? ? return o; 9 } 10 var funcs = outer(); 11 for (var k in funcs) { 12 ? ? funcs[k](); 13 } 14 var s = ''; 復(fù)制代碼 相當(dāng)于每次i是以一個(gè)副本的方式重新復(fù)制了一番,這個(gè)是可以達(dá)到我們的目的,但是有時(shí)候會(huì)對(duì)性能有一點(diǎn)影響,我們還是需要注意。
我們這里就不扯遠(yuǎn)了,在扯遠(yuǎn)的話(huà)我估計(jì)也露餡了。。。呵呵,最后我們來(lái)說(shuō)一點(diǎn)應(yīng)用吧。
閉包的應(yīng)用
jquery時(shí)如何神奇的使用閉包的我現(xiàn)在還看不透,那是我1年后的任務(wù),我這不關(guān)注他。
我這里說(shuō)的應(yīng)用時(shí)原來(lái)項(xiàng)目過(guò)程中遇到的,所以沒(méi)有代碼,我這邊說(shuō)下問(wèn)題吧:
我們點(diǎn)擊一個(gè)按鈕,會(huì)向服務(wù)器發(fā)一個(gè)ajax請(qǐng)求,其中包含一些data,然后數(shù)據(jù)返回回來(lái)后我們又會(huì)用到開(kāi)始傳過(guò)去的一些data中的敏感信息,比如id。
這個(gè)時(shí)候一種比較笨的方法就是服務(wù)器給我們傳回來(lái),但是閉包出現(xiàn)后,我們便可以直接在函數(shù)中定義函數(shù),而使用我們之前的data即可。
該例子有段時(shí)間了,大家看不清楚也沒(méi)有關(guān)系啦。。。。
結(jié)語(yǔ)
葉大俠病了,求安慰,求按頂。。。。。
本文轉(zhuǎn)自葉小釵博客園博客,原文鏈接:http://www.cnblogs.com/yexiaochai/archive/2013/06/15/3137288.html,如需轉(zhuǎn)載請(qǐng)自行聯(lián)系原作者
咳咳,葉大俠病了,昨天晚上回家時(shí)候在車(chē)上就不舒服,果然回來(lái)就掛了,本來(lái)還想今天接著上班撐下去的。但是昨天又看到一個(gè)IT巨子掛了,所以果斷請(qǐng)了一個(gè)假!!!
但是早上7.00左右就迷迷糊糊的醒了,于是我在想我是不是該“身殘志堅(jiān)”一番。。。。
咳咳,以上玩笑,我們最近一起學(xué)習(xí)了很多CSS的東西,相信大家的CSS水平必定提高了吧???所以我們接下來(lái)一段時(shí)間來(lái)看看javascript吧,今天我們一起來(lái)看看閉包這個(gè)家伙!
本文參考:
http://www.cnblogs.com/TomXu/
http://www.cnblogs.com/lhb25/archive/2011/09/06/javascript-scope-chain.html
http://www.cnblogs.com/frankfang/archive/2011/08/03/2125663.html
http://www.cnblogs.com/xiaotie/archive/2011/08/03/2126145.html
執(zhí)行上下文(execution context)
又是上下文。。。無(wú)論是曾經(jīng)學(xué)習(xí).net時(shí)候的httpcontext,還是最近學(xué)習(xí)的block formatting context,都是上下文!
我們可以感覺(jué)到上下文的存在,就如感覺(jué)得到空氣一樣,我們卻將它拿不出來(lái),于是我們來(lái)看看執(zhí)行上下文吧。
每次當(dāng)控制器轉(zhuǎn)到ecmascript可執(zhí)行代碼的時(shí)候,就會(huì)進(jìn)入一個(gè)執(zhí)行上下文。 活動(dòng)的執(zhí)行上下文組在邏輯上為一個(gè)堆棧,堆棧最底部一定是全局上下文(global context),頂部便是當(dāng)前上下文 這個(gè)句話(huà)是很有玄機(jī)的哦,比如我們?cè)谝粋€(gè)函數(shù)環(huán)境中,我們首先用的是當(dāng)前變量,若是沒(méi)有就在父級(jí)函數(shù)中找,最后就在window中找。
PS:我們?cè)趯?xiě)博客時(shí)候,中文沒(méi)有問(wèn)題,突然打一個(gè)字母上,你會(huì)發(fā)現(xiàn)整行都下移了1/2px,各位知道神馬原因么???:)
eval在執(zhí)行時(shí)候會(huì)產(chǎn)生一個(gè)調(diào)用上下文的東東(calling context),所以eval中定義的變量會(huì)影響函數(shù)環(huán)境中的變量。
作用域
閉包有作用域鏈有很多說(shuō)不清道不明的關(guān)系,所以我們還是先看看作用域吧。
任何語(yǔ)言都會(huì)有作用域的概念,作用域便是變量與函數(shù)可訪(fǎng)問(wèn)范圍,簡(jiǎn)稱(chēng)變量與函數(shù)的生命周期。 javascript中分為全局與局部?jī)煞N,直白點(diǎn)window與function
復(fù)制代碼 var name = '葉小釵'; function func() { var id = '刀狂劍癡'; function alertId() { alert(id); } alertId(); } alert(name);//葉小釵 alert(id);//錯(cuò)誤 func(); //刀狂劍癡 alertId();//錯(cuò)誤 復(fù)制代碼 此處name屬于window屬性便是全局的(有些瀏覽器自帶name屬性小心陷阱!)
func也是全局的,但是func這個(gè)作用域鏈包含了全局的,所以他可以訪(fǎng)問(wèn)外部的,但是外部不能訪(fǎng)問(wèn)進(jìn)來(lái)。
鏈子。。。
在js中什么都是對(duì)象,函數(shù)和其它對(duì)象一樣擁有很多屬性,其中一個(gè)比較特殊的屬性是:
[[scope]],scope翻譯過(guò)來(lái)就是作用域,該屬性包含了函數(shù)被創(chuàng)建的作用域中的對(duì)象的集合:
于是傳說(shuō)中的作用域鏈誕生了,他決定了哪些數(shù)據(jù)能被哪些函數(shù)訪(fǎng)問(wèn)。
當(dāng)一個(gè)函數(shù)創(chuàng)建后,他的作用域鏈會(huì)被創(chuàng)建此函數(shù)的作用域中可訪(fǎng)問(wèn)的數(shù)據(jù)對(duì)象填充:
function add (a, b) { var sum = a + b; return sum; } 在函數(shù)add創(chuàng)建時(shí),他的作用域鏈中會(huì)填入一個(gè)全局對(duì)象,我們可以想象為window被壓入了其[[scope]]
函數(shù)add的作用域在調(diào)用時(shí)會(huì)被用到,此時(shí)會(huì)創(chuàng)建一個(gè)“運(yùn)行時(shí)上下文(execution context)”的內(nèi)部對(duì)象, 他定義了函數(shù)執(zhí)行時(shí)的環(huán)境,每個(gè)運(yùn)行時(shí)上下文都有自己的作用域鏈,用于標(biāo)識(shí)符解析, 當(dāng)execution context創(chuàng)建時(shí),而他的作用域鏈初始化為當(dāng)前運(yùn)行函數(shù)的[[scope]]所包含的對(duì)象。 所有相關(guān)的東東會(huì)按照其在函數(shù)中出現(xiàn)的順序被復(fù)制到運(yùn)行時(shí)上下文的作用域鏈中,他們共同組成了“活動(dòng)對(duì)象(activation object)”,該對(duì)象就包含了函數(shù)的所有局部變量,參數(shù),以及this,然后會(huì)排在我們作用域堆棧的頂端,我們可以最先獲取,在運(yùn)行時(shí)上下文結(jié)束(函數(shù)執(zhí)行完畢)后,GC便會(huì)回收其空間。
在函數(shù)執(zhí)行過(guò)程中,遇到一個(gè)變量便會(huì)經(jīng)歷一次標(biāo)識(shí)符解析以決定從哪里獲取以及存儲(chǔ)數(shù)據(jù)。
這個(gè)過(guò)程首先從我們的“堆棧”頂端開(kāi)始搜索,也就是活動(dòng)對(duì)象的開(kāi)始,若是有該變量便獲取值,
若是沒(méi)有則向下,知道window為止,沒(méi)有就報(bào)錯(cuò)!
內(nèi)存溢出
是想我們的瀏覽器內(nèi)存若是搞滿(mǎn)了,自然會(huì)瀏覽器崩潰,這是我們閉包之中需要考慮到的東西,因?yàn)樗麜?huì)導(dǎo)致我們一些東西無(wú)法GC。
閉包,神奇的魔法
閉包是神奇的魔法,因?yàn)樗闪撕芏唷皦氖隆?#xff0c;達(dá)到了出人意料的結(jié)果。
所謂閉包,便是function嵌套function,內(nèi)部function可以訪(fǎng)問(wèn)外部的變量。 若是外部函數(shù)返回了內(nèi)部函數(shù),那么就閉了一個(gè)包 復(fù)制代碼 1 function a() { 2 ? ? var name = '葉小釵'; 3 ? ? function alertName() { 4 ? ? ? ? alert(name); 5 ? ? } 6 ? ? return alertName; 7 } 8? 9 var func = a(); 10 func();//葉小釵 復(fù)制代碼 這個(gè)家伙是個(gè)壞孩子,怎么說(shuō)呢,壞孩子招人疼啊!
我們看第9行,按我們之前的理解a執(zhí)行結(jié)束后,整個(gè)活動(dòng)對(duì)象是不是該被銷(xiāo)毀?是不是與a有關(guān)的東西都該GC呢?
確實(shí)是這樣的,但是我們這里就產(chǎn)生了一個(gè)閉包,阻止了其銷(xiāo)毀,因?yàn)樗锩娴淖兞勘挥玫搅恕?
這里的一個(gè)事實(shí)便是外部的func訪(fǎng)問(wèn)到了a內(nèi)部的變量!
一個(gè)經(jīng)典的例子:
復(fù)制代碼 1 function outer() { 2 ? ? var o = {}; 3 ? ? for (var i = 0; i < 10; i++) { 4 ? ? ? ? o[i] = function () { 5 ? ? ? ? ? ? alert(i); 6 ? ? ? ? } 7 ? ? } 8 ? ? return o; 9 } 10 var funcs = outer(); 11 for (var k in funcs) { 12 ? ? funcs[k](); 13 } 14 var s = ''; 復(fù)制代碼 我們來(lái)看這個(gè),大家應(yīng)該都比較熟悉了,我們知道他全部會(huì)打印10。
這是因?yàn)槲覀儗uter給予funcs時(shí)候,outer的任務(wù)就完成啦,他現(xiàn)在內(nèi)部的i便是10,我們現(xiàn)在再來(lái)調(diào)用函數(shù),所有的i自然是指向一個(gè)[[scope]],所以變量i就是10!!!
要怎么解決大家也一目了然:
復(fù)制代碼 1 function outer() { 2 ? ? var o = {}; 3 ? ? for (var i = 0; i < 10; i++) { 4 ? ? ? ? o[i] = (function (i) { 5 ? ? ? ? ? ? alert(i); 6 ? ? ? ? })(i) 7 ? ? } 8 ? ? return o; 9 } 10 var funcs = outer(); 11 for (var k in funcs) { 12 ? ? funcs[k](); 13 } 14 var s = ''; 復(fù)制代碼 相當(dāng)于每次i是以一個(gè)副本的方式重新復(fù)制了一番,這個(gè)是可以達(dá)到我們的目的,但是有時(shí)候會(huì)對(duì)性能有一點(diǎn)影響,我們還是需要注意。
我們這里就不扯遠(yuǎn)了,在扯遠(yuǎn)的話(huà)我估計(jì)也露餡了。。。呵呵,最后我們來(lái)說(shuō)一點(diǎn)應(yīng)用吧。
閉包的應(yīng)用
jquery時(shí)如何神奇的使用閉包的我現(xiàn)在還看不透,那是我1年后的任務(wù),我這不關(guān)注他。
我這里說(shuō)的應(yīng)用時(shí)原來(lái)項(xiàng)目過(guò)程中遇到的,所以沒(méi)有代碼,我這邊說(shuō)下問(wèn)題吧:
我們點(diǎn)擊一個(gè)按鈕,會(huì)向服務(wù)器發(fā)一個(gè)ajax請(qǐng)求,其中包含一些data,然后數(shù)據(jù)返回回來(lái)后我們又會(huì)用到開(kāi)始傳過(guò)去的一些data中的敏感信息,比如id。
這個(gè)時(shí)候一種比較笨的方法就是服務(wù)器給我們傳回來(lái),但是閉包出現(xiàn)后,我們便可以直接在函數(shù)中定義函數(shù),而使用我們之前的data即可。
該例子有段時(shí)間了,大家看不清楚也沒(méi)有關(guān)系啦。。。。
結(jié)語(yǔ)
葉大俠病了,求安慰,求按頂。。。。。
本文轉(zhuǎn)自葉小釵博客園博客,原文鏈接:http://www.cnblogs.com/yexiaochai/archive/2013/06/15/3137288.html,如需轉(zhuǎn)載請(qǐng)自行聯(lián)系原作者
總結(jié)
以上是生活随笔為你收集整理的【初窥javascript奥秘之闭包】叶大侠病都好了,求不踩了:)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 国产科幻片《流浪地球 2》南非定档 3
- 下一篇: JS 状态模式