欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

淺談JavaScript的閉包函數(shù)

 更新時(shí)間:2016年12月08日 12:07:11   作者:918之初  
閉包是有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域中的變量的函數(shù)。首先要明白的就是,閉包是函數(shù)。由于要求它可以訪問(wèn)另一個(gè)函數(shù)的作用于中的變量,所以我們往往是在一個(gè)函數(shù)的內(nèi)部創(chuàng)建另一個(gè)函數(shù),而“另一個(gè)函數(shù)”就是閉包。本文對(duì)其進(jìn)行系統(tǒng)分析,需要的朋友可以看下

 在JavaScript中,閉包恐怕是很多人不能理解的一個(gè)概念了,甚至很多人也會(huì)把閉包和匿名函數(shù)混淆。

 閉包是有權(quán)訪問(wèn)另一個(gè)函數(shù)作用域中的變量的函數(shù)。首先要明白的就是,閉包是函數(shù)。由于要求它可以訪問(wèn)另一個(gè)函數(shù)的作用于中的變量,所以我們往往是在一個(gè)函數(shù)的內(nèi)部創(chuàng)建另一個(gè)函數(shù),而“另一個(gè)函數(shù)”就是閉包。

 比如之前提到過(guò)的作為比較函數(shù):

  function createComparisonFunction(propertyName){
   return function(object1,object2){
    var value1=object1[propertyName];
    var value2=object2[propertyName];
    if(value1<value2){ return="" -1;="" }else="" if(value1="">value2){
     return 1;
    }else{
     return 0;
    }
   };
  }
</value2){>

 在這個(gè)函數(shù)中,由于return的函數(shù)它訪問(wèn)了包含函數(shù)(外部函數(shù))的變量propertyName,所以我們認(rèn)為這個(gè)函數(shù)即為閉包。即使這個(gè)閉包被返回了,而且是在其他地方調(diào)用了,但是它仍然可以訪問(wèn)propertyName,之所以還能夠訪問(wèn)到propertyName這個(gè)變量,是因?yàn)閮?nèi)部函數(shù)(閉包)的作用域鏈中包含著createComparisonFunction函數(shù)的作用域。因此,要徹底搞清楚閉包,就需要徹底搞清楚函數(shù)被調(diào)用時(shí)發(fā)生了什么以及作用域鏈的有關(guān)知識(shí)。

 當(dāng)某個(gè)函數(shù)被調(diào)用時(shí),會(huì)創(chuàng)建一個(gè)執(zhí)行環(huán)境(函數(shù)一旦被調(diào)用,則進(jìn)入函數(shù)執(zhí)行環(huán)境)和相應(yīng)的作用域鏈(作用域鏈?zhǔn)请S著執(zhí)行環(huán)境的不同而動(dòng)態(tài)變化的)。(對(duì)于函數(shù)而言)之后使用arguments其他命名參數(shù)的值來(lái)初始化函數(shù)的活動(dòng)對(duì)象(每個(gè)執(zhí)行環(huán)境都有一個(gè)變量對(duì)象,對(duì)于函數(shù)成為活動(dòng)對(duì)象)。對(duì)于有閉包的函數(shù)而言,在作用域鏈中,外部函數(shù)的活動(dòng)對(duì)象始終處于第二位,外部函數(shù)的外部函數(shù)的活動(dòng)對(duì)象始終處于第三位。。。直至作為作用域鏈終點(diǎn)的全局執(zhí)行環(huán)境。

 下面撇開(kāi)閉包不談,先通過(guò)一個(gè)簡(jiǎn)單的例子來(lái)理解作用域鏈以及變量對(duì)象和活動(dòng)對(duì)象。

 function compare(value1,value2){
 if(value1<value2){
  return -1;
 }else if(value1>value2){
  return 1;
 }else{
  return 0;
 }
}<br>         var result=compare(5,10);

    以上代碼首先定義了compare()函數(shù),然后又在全局作用域中調(diào)用了它。當(dāng)調(diào)用compare函數(shù)時(shí),首先創(chuàng)建一個(gè)函數(shù)執(zhí)行環(huán)境,每個(gè)執(zhí)行環(huán)境又對(duì)應(yīng)這一個(gè)變量對(duì)象,也就是說(shuō)作用域鏈和函數(shù)執(zhí)行環(huán)境是同時(shí)創(chuàng)建的,其中作用域鏈的前端即為compare函數(shù)的活動(dòng)對(duì)象(在函數(shù)中,變量對(duì)象又稱為活動(dòng)對(duì)象)。在compare活動(dòng)對(duì)象中包含了arguments、value1、value2(關(guān)鍵:盡管arguments數(shù)組對(duì)象包含value1和value2,但是我們還是要分開(kāi)列舉,而不是僅僅認(rèn)為只有arguments包含于compare的活動(dòng)對(duì)象,因?yàn)関alue1和value2也包含于compare的活動(dòng)對(duì)象)。

 對(duì)于上述代碼而言,全局執(zhí)行環(huán)境的變量對(duì)象(再次聲明:每一個(gè)執(zhí)行環(huán)境都存在相應(yīng)的變量對(duì)象)中包含result和compare,該變量對(duì)象在compare()執(zhí)行環(huán)境的作用域鏈的第二位。

 當(dāng)我們創(chuàng)建compare()函數(shù)時(shí),會(huì)創(chuàng)建一個(gè)預(yù)先包含全局變量對(duì)象的作用域鏈,這個(gè)作用域鏈被保存在compare函數(shù)內(nèi)部的[[scope]]屬性中,當(dāng)調(diào)用compare函數(shù)時(shí),會(huì)為函數(shù)創(chuàng)建一個(gè)執(zhí)行環(huán)境,然后通過(guò)復(fù)制函數(shù)的[[scope]]屬性中的對(duì)象構(gòu)建起執(zhí)行環(huán)境的作用域鏈。如下:

  作用域鏈的本質(zhì)就是一個(gè)指向變量對(duì)象的指針列表,它只引用但不實(shí)際包含變量對(duì)象。無(wú)論什么時(shí)候在函數(shù)中訪問(wèn)一個(gè)變量,就會(huì)從作用域鏈的前端沿著作用域鏈搜索具有相應(yīng)名字的變量。我們知道,全局環(huán)境的變量對(duì)象始終存在,而局部環(huán)境(如compare()函數(shù)執(zhí)行環(huán)境)的變量對(duì)象只在函數(shù)執(zhí)行的時(shí)候存在,一旦執(zhí)行完畢,局部變量對(duì)象(活動(dòng)對(duì)象)就會(huì)被銷毀。但在閉包中,卻與此不同。

  把博文開(kāi)始的代碼復(fù)制如下:

 function createComparisonFunction(propertyName){
 return function(object1,object2){
  var value1=object1[propertyName];
  var value2=object2[propertyName];
  if(value1<value2){
   return -1;
  }else if(value1>value2){
   return 1;
  }else{
   return 0;
  }
 };
}

由于在一個(gè)函數(shù)內(nèi)部定義的函數(shù)會(huì)將包含函數(shù)(即外部函數(shù))的活動(dòng)對(duì)象添加到它的作用域鏈中。因此,在createComparisonFunction函數(shù)內(nèi)部定義的匿名函數(shù)的作用域中實(shí)際包含著外部函數(shù)的活動(dòng)對(duì)象。如果我們執(zhí)行如下代碼:

var compare=createComparisonFunction("name");
var result=compare({name:"zzw"},{name:"ht"});

這時(shí)候匿名函數(shù)的作用域鏈將引用著外部函數(shù)的活動(dòng)對(duì)象。因?yàn)槟涿瘮?shù)從外部函數(shù)中被返回后,它的作用域鏈被初始化為包含外部函數(shù)的活動(dòng)對(duì)象和全局變量對(duì)象。這樣,匿名函數(shù)就可以訪問(wèn)外部函數(shù)中定義的所有變量。更為重要的是,即使外部函數(shù)在執(zhí)行完畢后,其活動(dòng)對(duì)象也不會(huì)被銷毀,因?yàn)槟涿瘮?shù)的作用域鏈仍然在引用這個(gè)活動(dòng)對(duì)象。換句話說(shuō),當(dāng)createComparison()函數(shù)返回后,其執(zhí)行環(huán)境的作用域鏈會(huì)被銷毀,但是她的活動(dòng)對(duì)象仍然保存在內(nèi)存中。等到倪敏函數(shù)被銷毀后,外部函數(shù)的活動(dòng)對(duì)象才會(huì)被銷毀。

由于閉包會(huì)攜帶者包含他的函數(shù)的作用域,因此回避其他函數(shù)占用更多的內(nèi)存。過(guò)度的使用閉包可能會(huì)導(dǎo)致內(nèi)存占用過(guò)多,我們建議只在絕對(duì)必要的時(shí)候再考慮使用閉包。

模仿塊級(jí)作用域

(function(){
 var now=new Date();
 if(now.getMonth()==0&&now.getDate()==1){
  alert("happy new year");
 }
})();

這就是模仿塊級(jí)作用域,即定義并立即調(diào)用了一個(gè)匿名函數(shù)。

如下為演示其作用:

function outputNumbers(count){
 (function(){
  for (var i=0;i<count;i++){
   console.log(i);
  }
 })();
 console.log(i);
}
outputNumbers(5);

這是在模仿塊級(jí)作用域之外的console.log(i)就會(huì)導(dǎo)致錯(cuò)誤,因?yàn)閕未被定義。說(shuō)明在執(zhí)行了模仿塊級(jí)作用域之后,內(nèi)部的變量就被銷毀了。

以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流,同時(shí)也希望多多支持腳本之家!

相關(guān)文章

最新評(píng)論