日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

深入理解JavaScript的闭包特性如何给循环中的对象添加事件

發(fā)布時間:2024/4/17 javascript 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 深入理解JavaScript的闭包特性如何给循环中的对象添加事件 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

初學者經(jīng)常碰到的,即獲取HTML元素集合,循環(huán)給元素添加事件。在事件響應函數(shù)中(event handler)獲取對應的索引。但每次獲取的都是最后一次循環(huán)的索引。原因是初學者并未理解JavaScript的閉包特性。

有個網(wǎng)友問了個問題,如下的html,為什么點擊所有的段落p輸出都是5,而不是alert出對應的0,1,2,3,4。

1.? <!DOCTYPE?HTML>

2.? <html>

3.? <head>

4.? <meta?charset="utf-8"?/>

5.? <title>閉包演示</title>

6.? <style?type="text/css">

7.? ????p?{background:gold;}

8.? </style>

9.? <script?type="text/javascript">

10.function?init()?{

11.????var?pAry?=?document.getElementsByTagName("p");

12.????for(?var?i=0;?i<pAry.length;?i++?)?{

13.?????????pAry[i].onclick?=?function()?{

14.?????????alert(i);

15.????}

16.??}

17.}

18.</script>

19.</head>

20.<body?οnlοad="init();">

21.<p>產(chǎn)品?0</p>

22.<p>產(chǎn)品?1</p>

23.<p>產(chǎn)品?2</p>

24.<p>產(chǎn)品?3</p>

25.<p>產(chǎn)品?4</p>

26.</body>

27.</html>

以上場景是初學者經(jīng)常碰到的。即獲取HTML元素集合,循環(huán)給元素添加事件。在事件響應函數(shù)中(event handler)獲取對應的索引。但每次獲取的都是最后一次循環(huán)的索引。

原因是初學者并未理解JavaScript的閉包特性。通過element.οnclick=function(){alert(i);}方式給元 素添加點擊事件。響應函數(shù)function(){alert(i);}中的 i 并非每次循環(huán)時對應的 i(如0,1,2,3,4)而是循環(huán)后最后 i 的值5。 或者說循環(huán)時響應函數(shù)內(nèi)并未能保存對應的值 i,而是最后一次i++的值5。

了解了原因,下面就由幾種方式可與解決:

1、將變量 i 保存給在每個段落對象(p)上

1.? function?init1()?{

2.? ??var?pAry?=?document.getElementsByTagName("p");

3.? ??for(?var?i=0;?i<pAry.length;?i++?)?{

4.? ?????pAry[i].i?=?i;

5.? ?????pAry[i].onclick?=?function()?{

6.? ????????alert(this.i);

7.? ?????}

8.? ??}

9.? }

2、將變量 i 保存在匿名函數(shù)自身

1.? function?init2()?{

2.? ??var?pAry?=?document.getElementsByTagName("p");

3.? ??for(?var?i=0;?i<pAry.length;?i++?)?{

4.? ???(pAry[i].onclick?=?function()?{

5.? ????????alert(arguments.callee.i);

6.? ????}).i?=?i;

7.? ??}

8.? }

3、加一層閉包,i 以函數(shù)參數(shù)形式傳遞給內(nèi)層函數(shù)

1.? function?init3()?{

2.? ??var?pAry?=?document.getElementsByTagName("p");

3.? ??for(?var?i=0;?i<pAry.length;?i++?)?{

4.? ???(function(arg){

5.? ???????pAry[i].onclick?=?function()?{

6.? ??????????alert(arg);

7.? ???????};

8.? ???})(i);//調(diào)用時參數(shù)

9.? ??}

10.}

4、加一層閉包,i 以局部變量形式傳遞給內(nèi)層函數(shù)

1.? function?init4()?{

2.? ??var?pAry?=?document.getElementsByTagName("p");

3.? ??for(?var?i=0;?i<pAry.length;?i++?)?{

4.? ????(function?()?{

5.? ??????var?temp?=?i;//調(diào)用時局部變量

6.? ??????pAry[i].onclick?=?function()?{

7.? ????????alert(temp);

8.? ??????}

9.? ????})();

10.??}

11.}

5、加一層閉包,返回一個函數(shù)作為響應事件(注意與3的細微區(qū)別)

1.? function?init5()?{

2.? ??var?pAry?=?document.getElementsByTagName("p");

3.? ??for(?var?i=0;?i<pAry.length;?i++?)?{

4.? ???pAry[i].onclick?=?function(arg)?{

5.? ???????return?function()?{//返回一個函數(shù)

6.? ???????alert(arg);

7.? ?????}

8.? ???}(i);

9.? ??}

10.}

6、用Function實現(xiàn),實際上每產(chǎn)生一個函數(shù)實例就會產(chǎn)生一個閉包

1.? function?init6()?{

2.? ????var?pAry?=?document.getElementsByTagName("p");

3.? ????for(?var?i=0;?i<pAry.length;?i++?)?{

4.? ??????pAry[i].onclick?=?new?Function("alert("?+?i?+?");");//new一次就產(chǎn)生一個函數(shù)實例

5.? ????}

6.? }

7、用Function實現(xiàn),注意與6的區(qū)別

1.? function?init7()?{

2.? ????var?pAry?=?document.getElementsByTagName("p");

3.? ????for(?var?i=0;?i<pAry.length;?i++?)?{

4.? ?????????pAry[i].onclick?=?Function('alert('+i+')');

5.? ????}

6.? }

?

?

淺析Javascript閉包的特性

?

本文將對Javascript閉包的特性進行分析,并舉例進行說明。閉包,是指語法域位于某個特定的區(qū)域,具有持續(xù)參照(讀寫)位于該區(qū)域內(nèi)自身范圍之外的執(zhí)行域上的非持久型變量值能力的段落。

AD:

Javascript閉包的定義非常晦澀——閉包,是指語法域位于某個特定的區(qū)域,具有持續(xù)參照(讀寫)位于該區(qū)域內(nèi)自身范圍之外的執(zhí)行域上的非持久型變量值能力的段落。這些外部執(zhí)行域的非持久型變量神奇地保留它們在閉包最初定義(或創(chuàng)建)時的值(深連結(jié))。

簡單來說,Javascript閉包就是在另一個作用域中保存了一份它從上一級函數(shù)或作用域取得的變量(鍵值對),而這些鍵值對是不會隨上一級函數(shù)的執(zhí)行完成而銷毀。周愛民說得更清楚,閉包就是“屬性表”,閉包就是一個數(shù)據(jù)塊,閉包就是一個存放著“Name=Value”的對照表。就這么簡單。但是,必須強調(diào),閉包是運行期概念,一個函數(shù)實例。

Javascript閉包的實現(xiàn),通常是在函數(shù)內(nèi)部再定義函數(shù),讓該內(nèi)部函數(shù)使用上一級函數(shù)的變量或全局變量。

ECMAScript認為使用全局變量是一個簡單的Javascript閉包實例。

1.??var?sMessage?=?"Hello?World";? ?

2.??function?sayHelloWorld(){? ?

3.? alert(sMessage);? ?

4.? };? ?

5.? sayHelloWorld();?

但它完成沒有體現(xiàn)Javascript閉包的特性……

現(xiàn)在比較讓人認同的Javascript閉包實現(xiàn)有如下三種

1.??with(obj){? ?

2.? //這里是對象閉包? ?

3.? }(function(){???? ?

4.? //函數(shù)閉包? ?

5.? })()try{? ?

6.? //...? ?

7.? }?catch(e)?{? ?

8.? //catch閉包?但IE里不行? ?

9.? }?

附上今天在無憂看到的問題:

要求:

讓這三個節(jié)點的Onclick事件都能正確的彈出相應的參數(shù)。

1.??<ul>?? ?

2.??<li?id="a1">aa</li>?? ?

3.??<li?id="a2">aa</li>? ?

4.??<li?id="a3">aa</li>? ?

5.??</ul>? ?

6.??<script?type="text/javascript">? ?

7.??<ul>? ?

8.??<li?id="a1">aa</li>? ?

9.??<li?id="a2">aa</li>? ?

10.?<li?id="a3">aa</li>? ?

11.?</ul>? ?

12.?<script?type="text/javascript">? ?

13. for(var?i=1;?i?<?4;?i++){? ?

14. var?id?=?document.getElementById("a"?+?i);? ?

15. id.onclick?=?function(){? ?

16. alert(i);//現(xiàn)在都是返回4???? ?

17. }? ?

18. }? ?

19.?</script>?

客服果果的解答:

1.? for(var?i=1;?i?<?4;?i++){???? ?

2.? var?id?=?document.getElementById("a"?+?i);??? ?

3.? /*??? ?

4.? 這里生成了一個匿名函數(shù)并賦值給對象?id_i;??? ?

5.? */??? ?

6.? id.onclick?=?function(){???????? ?

7.? /*???????? ?

8.? 這個i來源于局部變量,無法以window.i或者obj.i的形式在后期引用,???????? ?

9.? 只好以指針或者變量地址方式保存在這個匿名函數(shù)中,???????? ?

10. 這就是傳說的閉包,所以所有這個過程中生成的事件句柄都使用引用???????? ?

11. 的方式來持久這個變量,也就是這些匿名函數(shù)共用一個變量i;???????? ?

12. */??????? ?

13. alert(i);???? ?

14. };? ?

15. };?

局部變?nèi)?/p>

1.??for(var?i=1;?i?<?4;?i++){? ?

2.? var?id?=?document.getElementById("a"?+?i);??? ?

3.? id.i=i;//這個i有了根??? ?

4.? id.οnclick=function(){???????? ?

5.? alert(this.i)???? ?

6.? };? ?

7.? };1.for(var?i=1;?i?<?4;?i++){??? ?

8.? var?id?=?document.getElementById("a"?+?i);?? ?

9.? window[id.id]=i;//這個i有了根?? ?

10. id.οnclick=function(){??????? ?

11. alert(window[this.id]);??? ?

12. };? ?

13. }?

產(chǎn)生一對一的更多Javascript閉包

1.??for(var?i=1;?i?<?4;?i++){?? ?

2.? var?id?=?document.getElementById("a"?+?i);?? ?

3.? id.onclick?=?new?function(){?????? ?

4.? var?i2=i;//這個i是閉包的閉包????? ?

5.??return?function(){????????? ?

6.? alert(i2);????? ?

7.? }??? ?

8.? };? ?

9.? }?

javascript深入理解js閉包發(fā)布:dxy 字體:[增加 減小] 類型:轉(zhuǎn)載

?

閉包(closure)是Javascript語言的一個難點,也是它的特色,很多高級應用都要依靠閉包實現(xiàn)。

一、變量的作用域

?

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

?

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

?

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

?

?

Js代碼

?

  var n=999;

?

  function f1(){

    alert(n);

  }

?

  f1(); // 999

?

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

?

Js代碼

?

  function f1(){

    var n=999;

  }

?

  alert(n); // error

?

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

?

Js代碼

?

  function f1(){

    n=999;

  }

?

  f1();

?

  alert(n); // 999

?

--------------------------------------------------------------------------------------------------------

?

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

?

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

?

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

?

Js代碼

?

  function f1(){

?

    n=999;

?

    function f2(){

      alert(n); // 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)部變量了嗎!

?

?

Js代碼

?

  function f1(){

?

    n=999;

?

    function f2(){

      alert(n);

    }

?

    return f2;

?

  }

?

  var result=f1();

?

  result(); // 999

?

--------------------------------------------------------------------------------------------------------

?

三、閉包的概念

?

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

?

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

?

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

?

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

?

--------------------------------------------------------------------------------------------------------b

?

四、閉包的用途

?

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

?

怎么來理解這句話呢?請看下面的代碼。

?

?

Js代碼

?

  function f1(){

?

    var 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被賦給了一個全局變量,這導致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相當于是一個setter,可以在函數(shù)外部對函數(shù)內(nèi)部的局部變量進行操作。

?

--------------------------------------------------------------------------------------------------------

?

五、使用閉包的注意點

?

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

?

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

?

改變父函數(shù)內(nèi)部變量的值。

?

--------------------------------------------------------------------------------------------------------

?

六、思考題

?

如果你能理解下面代碼的運行結(jié)果,應該就算理解閉包的運行機制了。

?

Js代碼

  var name = "The Window";

  var object = {

    name : "My Object",

    getNameFunc : function(){

      return function(){

        return this.name;

     };

    }

};

alert(object.getNameFunc()()); //The Window

?

--------------------------------------------------------------------------------------------------------

JavaScript閉包例子

?

function outerFun()

{

var a=0;

function innerFun()

{

a++;

alert(a);

}

}

innerFun()

?

上面的代碼是錯誤的.innerFun()的作用域在outerFun()內(nèi)部,所在outerFun()外部調(diào)用它是錯誤的.

?

改成如下,也就是閉包:

?

Js代碼

?

function outerFun()

{

var a=0;

function innerFun()

{

a++;

alert(a);

}

return innerFun; //注意這里

}

var obj=outerFun();

obj(); //結(jié)果為1

obj(); //結(jié)果為2

var obj2=outerFun();

obj2(); //結(jié)果為1

obj2(); //結(jié)果為2

?

什么是閉包:

?

當內(nèi)部函數(shù) 在定義它的作用域 的外部 被引用時,就創(chuàng)建了該內(nèi)部函數(shù)的閉包 ,如果內(nèi)部函數(shù)引用了位于外部函數(shù)的變量,當外部函數(shù)調(diào)用完畢后,這些變量在內(nèi)存不會被 釋放,因為閉包需要它們.

?

--------------------------------------------------------------------------------------------------------

?

再來看一個例子

?

Js代碼

?

function outerFun()

{

var a =0;

alert(a);

}

var a=4;

outerFun();

alert(a);

?

結(jié)果是 0,4 . 因為在函數(shù)內(nèi)部使用了var關(guān)鍵字 維護a的作用域在outFun()內(nèi)部.

?

再看下面的代碼:

?

Js代碼

?

function outerFun()

{

//沒有var

a =0;

alert(a);

}

var a=4;

outerFun();

alert(a);

結(jié)果為 0,0 真是奇怪,為什么呢?

?

作用域鏈是描述一種路徑的術(shù)語,沿著該路徑可以確定變量的值 .當執(zhí)行a=0時,因為沒有使用var關(guān)鍵字,因此賦值操作會沿著作用域鏈到var a=4; 并改變其值.

?

--------------------------------------------------------------------------------------------------------------------------------------------------

?

?

如果你對javascript閉包還不是很理解,那么請看下面轉(zhuǎn)載的文章:(轉(zhuǎn)載:http://www.felixwoo.com/archives/247)

?

?

?

一、什么是閉包?

?

官方”的解釋是:閉包是一個擁有許多變量和綁定了這些變量的環(huán)境的表達式(通常是一個函數(shù)),因而這些變量也是該表達式的一部分。

相信很少有人能直接看懂這句話,因為他描述的太學術(shù)。其實這句話通俗的來說就是:JavaScript中所有的function都是一個閉包。不過一般來說,嵌套的function所產(chǎn)生的閉包更為強大,也是大部分時候我們所謂的“閉包”。看下面這段代碼:

?

function a() {? var i = 0;? function b() { alert(++i); }? return b;}var c = a();c();這段代碼有兩個特點:

?

1、函數(shù)b嵌套在函數(shù)a內(nèi)部;

?

2、函數(shù)a返回函數(shù)b。

?

引用關(guān)系如圖:

?

?

?

  這樣在執(zhí)行完var c=a()后,變量c實際上是指向了函數(shù)b,再執(zhí)行c()后就會彈出一個窗口顯示i的值(第一次為1)。這段代碼其實就創(chuàng)建了一個閉包,為什么?因為函數(shù)a外的變量c引用了函數(shù)a內(nèi)的函數(shù)b,就是說:

?

  當函數(shù)a的內(nèi)部函數(shù)b被函數(shù)a外的一個變量引用的時候,就創(chuàng)建了一個閉包。

?

?

  讓我們說的更透徹一些。所謂“閉包”,就是在構(gòu)造函數(shù)體內(nèi)定義另外的函數(shù)作為目標對象的方法函數(shù),而這個對象的方法函數(shù)反過來引用外層函數(shù)體中的臨時變量。這使得只要目標 對象在生存期內(nèi)始終能保持其方法,就能間接保持原構(gòu)造函數(shù)體當時用到的臨時變量值。盡管最開始的構(gòu)造函數(shù)調(diào)用已經(jīng)結(jié)束,臨時變量的名稱也都消失了,但在目 標對象的方法內(nèi)卻始終能引用到該變量的值,而且該值只能通這種方法來訪問。即使再次調(diào)用相同的構(gòu)造函數(shù),但只會生成新對象和方法,新的臨時變量只是對應新 的值,和上次那次調(diào)用的是各自獨立的。

?

二、閉包有什么作用?

?

?

  簡而言之,閉包的作用就是在a執(zhí)行完并返回后,閉包使得Javascript的垃圾回收機制GC不會收回a所占用的資源,因為a的內(nèi)部函數(shù)b的執(zhí)行需要依賴a中的變量。這是對閉包作用的非常直白的描述,不專業(yè)也不嚴謹,但大概意思就是這樣,理解閉包需要循序漸進的過程。

?

在上面的例子中,由于閉包的存在使得函數(shù)a返回后,a中的i始終存在,這樣每次執(zhí)行c(),i都是自加1后alert出i的值。

?

  那 么我們來想象另一種情況,如果a返回的不是函數(shù)b,情況就完全不同了。因為a執(zhí)行完后,b沒有被返回給a的外界,只是被a所引用,而此時a也只會被b引 用,因此函數(shù)a和b互相引用但又不被外界打擾(被外界引用),函數(shù)a和b就會被GC回收。(關(guān)于Javascript的垃圾回收機制將在后面詳細介紹)

?

三、閉包內(nèi)的微觀世界

?

  如果要更加深入的了解閉包以及函數(shù)a和嵌套函數(shù)b的關(guān)系,我們需要引入另外幾個概念:函數(shù)的執(zhí)行環(huán)境(excution context)、活動對象(call object)、作用域(scope)、作用域鏈(scope chain)。以函數(shù)a從定義到執(zhí)行的過程為例闡述這幾個概念。

?

當定義函數(shù)a的時候,js解釋器會將函數(shù)a的作用域鏈(scope chain)設置為定義a時a所在的“環(huán)境”,如果a是一個全局函數(shù),則scope chain中只有window對象。

當執(zhí)行函數(shù)a的時候,a會進入相應的執(zhí)行環(huán)境(excution context)。

在創(chuàng)建執(zhí)行環(huán)境的過程中,首先會為a添加一個scope屬性,即a的作用域,其值就為第1步中的scope chain。即a.scope=a的作用域鏈。

然后執(zhí)行環(huán)境會創(chuàng)建一個活動對象(call object)。活動對象也是一個擁有屬性的對象,但它不具有原型而且不能通過JavaScript代碼直接訪問。創(chuàng)建完活動對象后,把活動對象添加到a的作用域鏈的最頂端。此時a的作用域鏈包含了兩個對象:a的活動對象和window對象。

下一步是在活動對象上添加一個arguments屬性,它保存著調(diào)用函數(shù)a時所傳遞的參數(shù)。

最后把所有函數(shù)a的形參和內(nèi)部的函數(shù)b的引用也添加到a的活動對象上。在這一步中,完成了函數(shù)b的的定義,因此如同第3步,函數(shù)b的作用域鏈被設置為b所被定義的環(huán)境,即a的作用域。

到此,整個函數(shù)a從定義到執(zhí)行的步驟就完成了。此時a返回函數(shù)b的引用給c,又函數(shù)b的作用域鏈包含了對函數(shù)a的活動對象的引用,也就是說b可以訪問到a中定義的所有變量和函數(shù)。函數(shù)b被c引用,函數(shù)b又依賴函數(shù)a,因此函數(shù)a在返回后不會被GC回收。

?

當函數(shù)b執(zhí)行的時候亦會像以上步驟一樣。因此,執(zhí)行時b的作用域鏈包含了3個對象:b的活動對象、a的活動對象和window對象,如下圖所示:

?

?

?

如圖所示,當在函數(shù)b中訪問一個變量的時候,搜索順序是:

?

先搜索自身的活動對象,如果存在則返回,如果不存在將繼續(xù)搜索函數(shù)a的活動對象,依次查找,直到找到為止。

如果函數(shù)b存在prototype原型對象,則在查找完自身的活動對象后先查找自身的原型對象,再繼續(xù)查找。這就是Javascript中的變量查找機制。

如果整個作用域鏈上都無法找到,則返回undefined。

小結(jié),本段中提到了兩個重要的詞語:函數(shù)的定義與執(zhí)行。文中提到函數(shù)的作用域是在定義函數(shù)時候就已經(jīng)確定,而不是在執(zhí)行的時候確定(參看步驟1和3)。用一段代碼來說明這個問題:

?

function f(x) {?? var g = function () { return x; }? return g;}var h = f(1);alert(h()); 這段代碼中變量h指向了f中的那個匿名函數(shù)(由g返回)。

?

假設函數(shù)h的作用域是在執(zhí)行alert(h())確定的,那么此時h的作用域鏈是:h的活動對象->alert的活動對象->window對象。

假設函數(shù)h的作用域是在定義時確定的,就是說h指向的那個匿名函數(shù)在定義的時候就已經(jīng)確定了作用域。那么在執(zhí)行的時候,h的作用域鏈為:h的活動對象->f的活動對象->window對象。

如果第一種假設成立,那輸出值就是undefined;如果第二種假設成立,輸出值則為1。

?

運行結(jié)果證明了第2個假設是正確的,說明函數(shù)的作用域確實是在定義這個函數(shù)的時候就已經(jīng)確定了。

?

?

?

四、閉包的應用場景

保護函數(shù)內(nèi)的變量安全。以最開始的例子為例,函數(shù)a中i只有函數(shù)b才能訪問,而無法通過其他途徑訪問到,因此保護了i的安全性。

?

在內(nèi)存中維持一個變量。依然如前例,由于閉包,函數(shù)a中i的一直存在于內(nèi)存中,因此每次執(zhí)行c(),都會給i自加1。

通過保護變量的安全實現(xiàn)JS私有屬性和私有方法(不能被外部訪問)

私有屬性和方法在Constructor外是無法被訪問的

function Constructor(...) {

var that = this;

var membername = value;

function membername(...) {...}

}

?

以上3點是閉包最基本的應用場景,很多經(jīng)典案例都源于此。

?

?

?

五、Javascript的垃圾回收機制

?

?

在Javascript中,如果一個對象不再被引用,那么這個對象就會被GC回收。如果兩個對象互相引用,而不再被第3者所引用,那么這兩個互相引用的對象也會被回收。因為函數(shù)a被b引用,b又被a外的c引用,這就是為什么函數(shù)a執(zhí)行后不會被回收的原因。

?

?

六、結(jié)語

?

理解JavaScript的閉包是邁向高級JS程序員的必經(jīng)之路,理解了其解釋和運行機制才能寫出更為安全和優(yōu)雅的代碼。

轉(zhuǎn)載于:https://www.cnblogs.com/08291018wan/p/5757657.html

總結(jié)

以上是生活随笔為你收集整理的深入理解JavaScript的闭包特性如何给循环中的对象添加事件的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。