国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 語(yǔ)言 > JavaScript > 正文

Javascript閉包(Closure)詳解

2024-05-06 16:19:20
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

閉包(closure)是Javascript語(yǔ)言的一個(gè)難點(diǎn),也是它的特色,很多高級(jí)應(yīng)用都要依靠閉包實(shí)現(xiàn)。

下面就是我的學(xué)習(xí)筆記,對(duì)于Javascript初學(xué)者應(yīng)該是很有用的。

一、變量的作用域

要理解閉包,首先必須理解Javascript特殊的變量作用域。

變量的作用域無(wú)非就是兩種:全局變量和局部變量。

Javascript語(yǔ)言的特殊之處,就在于函數(shù)內(nèi)部可以直接讀取全局變量。

 

 
  1. var n=999; 
  2.  
  3. function f1(){ 
  4.   alert(n); 
  5.  
  6. f1(); // 999 

另一方面,在函數(shù)外部自然無(wú)法讀取函數(shù)內(nèi)的局部變量。

 

 
  1. function f1(){ 
  2.   var n=999; 
  3.  
  4. alert(n); // error 

這里有一個(gè)地方需要注意,函數(shù)內(nèi)部聲明變量的時(shí)候,一定要使用var命令。如果不用的話,你實(shí)際上聲明了一個(gè)全局變量!

 

 
  1. function f1(){ 
  2.   n=999; 
  3.  
  4. f1(); 
  5.  
  6. alert(n); // 999 

二、如何從外部讀取局部變量?

出于種種原因,我們有時(shí)候需要得到函數(shù)內(nèi)的局部變量。但是,前面已經(jīng)說(shuō)過(guò)了,正常情況下,這是辦不到的,只有通過(guò)變通方法才能實(shí)現(xiàn)。

那就是在函數(shù)的內(nèi)部,再定義一個(gè)函數(shù)。

 

 
  1. function f1(){ 
  2.  
  3.   var n=999; 
  4.  
  5.   function f2(){ 
  6.     alert(n); // 999 
  7.   } 
  8.  

在上面的代碼中,函數(shù)f2就被包括在函數(shù)f1內(nèi)部,這時(shí)f1內(nèi)部的所有局部變量,對(duì)f2都是可見的。但是反過(guò)來(lái)就不行,f2內(nèi)部的局部變量,對(duì)f1就是不可見的。這就是Javascript語(yǔ)言特有的"鏈?zhǔn)阶饔糜?quot;結(jié)構(gòu)(chain scope),子對(duì)象會(huì)一級(jí)一級(jí)地向上尋找所有父對(duì)象的變量。所以,父對(duì)象的所有變量,對(duì)子對(duì)象都是可見的,反之則不成立。

既然f2可以讀取f1中的局部變量,那么只要把f2作為返回值,我們不就可以在f1外部讀取它的內(nèi)部變量了嗎!

 

 
  1. function f1(){ 
  2.  
  3.   var n=999; 
  4.  
  5.   function f2(){ 
  6.     alert(n);  
  7.   } 
  8.  
  9.   return f2; 
  10.  
  11.  
  12. var result=f1(); 
  13.  
  14. result(); // 999 

三、閉包的概念

上一節(jié)代碼中的f2函數(shù),就是閉包。

各種專業(yè)文獻(xiàn)上的"閉包"(closure)定義非常抽象,很難看懂。我的理解是,閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)。

由于在Javascript語(yǔ)言中,只有函數(shù)內(nèi)部的子函數(shù)才能讀取局部變量,因此可以把閉包簡(jiǎn)單理解成"定義在一個(gè)函數(shù)內(nèi)部的函數(shù)"。

所以,在本質(zhì)上,閉包就是將函數(shù)內(nèi)部和函數(shù)外部連接起來(lái)的一座橋梁。

四、閉包的用途

閉包可以用在許多地方。它的最大用處有兩個(gè),一個(gè)是前面提到的可以讀取函數(shù)內(nèi)部的變量,另一個(gè)就是讓這些變量的值始終保持在內(nèi)存中。

怎么來(lái)理解這句話呢?請(qǐng)看下面的代碼。

 

 
  1. function f1(){ 
  2.  
  3.   var n=999; 
  4.  
  5.   nAdd=function(){n+=1} 
  6.  
  7.   function f2(){ 
  8.     alert(n); 
  9.   } 
  10.  
  11.   return f2; 
  12.  
  13.  
  14. var result=f1(); 
  15.  
  16. result(); // 999 
  17.  
  18. nAdd(); 
  19.  
  20. result(); // 1000 

在這段代碼中,result實(shí)際上就是閉包f2函數(shù)。它一共運(yùn)行了兩次,第一次的值是999,第二次的值是1000。這證明了,函數(shù)f1中的局部變量n一直保存在內(nèi)存中,并沒有在f1調(diào)用后被自動(dòng)清除。

為什么會(huì)這樣呢?原因就在于f1是f2的父函數(shù),而f2被賦給了一個(gè)全局變量,這導(dǎo)致f2始終在內(nèi)存中,而f2的存在依賴于f1,因此f1也始終在內(nèi)存中,不會(huì)在調(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ù)外部對(duì)函數(shù)內(nèi)部的局部變量進(jìn)行操作。

五、使用閉包的注意點(diǎn)

1)由于閉包會(huì)使得函數(shù)中的變量都被保存在內(nèi)存中,內(nèi)存消耗很大,所以不能濫用閉包,否則會(huì)造成網(wǎng)頁(yè)的性能問(wèn)題,在IE中可能導(dǎo)致內(nèi)存泄露。解決方法是,在退出函數(shù)之前,將不使用的局部變量全部刪除。

2)閉包會(huì)在父函數(shù)外部,改變父函數(shù)內(nèi)部變量的值。所以,如果你把父函數(shù)當(dāng)作對(duì)象(object)使用,把閉包當(dāng)作它的公用方法(Public Method),把內(nèi)部變量當(dāng)作它的私有屬性(private value),這時(shí)一定要小心,不要隨便改變父函數(shù)內(nèi)部變量的值。

六、思考題

如果你能理解下面兩段代碼的運(yùn)行結(jié)果,應(yīng)該就算理解閉包的運(yùn)行機(jī)制了。

代碼片段一

 

 
  1. var name = "The Window"
  2.  
  3. var object = { 
  4.   name : "My Object"
  5.  
  6.   getNameFunc : function(){ 
  7.     return function(){ 
  8.       return this.name; 
  9.     }; 
  10.  
  11.   } 
  12.  
  13. }; 
  14.  
  15. alert(object.getNameFunc()()); 

代碼片段二

 

 
  1. var name = "The Window"
  2.  
  3. var object = { 
  4.   name : "My Object"
  5.  
  6.   getNameFunc : function(){ 
  7.     var that = this
  8.     return function(){ 
  9.       return that.name; 
  10.     }; 
  11.  
  12.   } 
  13.  
  14. }; 
  15.  
  16. alert(object.getNameFunc()());   

以上所述就是本文的全部?jī)?nèi)容了,希望大家能夠喜歡。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表

圖片精選

主站蜘蛛池模板: 洪雅县| 洛阳市| 罗山县| 当阳市| 东山县| 阿勒泰市| 洞头县| 柳江县| 永兴县| 大丰市| 九龙城区| 宣武区| 班戈县| 同江市| 犍为县| 芒康县| 乌鲁木齐县| 崇明县| 庆安县| 海城市| 桃源县| 广河县| 墨脱县| 阳西县| 会理县| 汝州市| 交口县| 西吉县| 浪卡子县| 永吉县| 古丈县| 天气| 黄梅县| 天镇县| 玉屏| 霍林郭勒市| 云南省| 白水县| 阳江市| 阿克陶县| 南漳县|