最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript 閉包機(jī)制詳解及實例代碼

 更新時間:2016年10月10日 15:43:28   作者:cy012124  
這篇文章主要介紹了JavaScript 閉包機(jī)制詳解及實例代碼的相關(guān)資料,需要的朋友可以參考下

首先要區(qū)分兩個概念,一是匿名函數(shù),一是閉包。

所謂匿名函數(shù),就是創(chuàng)建函數(shù)沒有給定函數(shù)名。經(jīng)常出現(xiàn)的包括函數(shù)表達(dá)式,就是定義一個匿名函數(shù),然后將函數(shù)賦值給某個變量,而此時這個變量就相當(dāng)于該函數(shù)的函數(shù)名,例如:

var sayHi = function(){
  alert("Hi");
}; //注意這個分號
sayHi(); //調(diào)用函數(shù)

還有一種常用匿名函數(shù)的情況是回調(diào)函數(shù),如 JQuery 中常用到的:

$("p").click(function(){
  alert("click");
});

此外,還有利用匿名函數(shù)作為某函數(shù)的返回值:

function sayNameWithAge(age){
  return function(person){
    if(person.age == age){
      return person.name;
    }
  }
}

那么,閉包又是怎么一回事呢?所謂的閉包,其實就是一個函數(shù),而這個函數(shù)有一點(diǎn)比較特別,它有權(quán)能夠去訪問其他函數(shù)作用域的變量。

從定義中我們發(fā)現(xiàn),其實在上面的匿名函數(shù)例子中,就存在這樣的閉包。在最后一個例子中,匿名函數(shù)訪問了函數(shù) sayNameWithAge 的參數(shù) age,那么,這個作為返回值的匿名函數(shù)就是一個閉包。

要徹底理解閉包,就必須理解函數(shù)調(diào)用時的整個機(jī)制,這里從作用域鏈的相關(guān)知識來進(jìn)行講解。

首先看下面的例子:

function sayName(name){
  alert(name);
}
sayName("Jack");

在上面的函數(shù) sayName 被調(diào)用的時候,就會創(chuàng)建一個對應(yīng)的執(zhí)行環(huán)境和作用域鏈,如下圖所示:

當(dāng) sayName 函數(shù)被調(diào)用時,創(chuàng)建了相應(yīng)的作用域鏈,而作用域中包含兩個引用分別指向兩個對象,其中一個是全局變量對象,這個全局對象是在函數(shù)創(chuàng)建的時候就已經(jīng)創(chuàng)建了,只是在調(diào)用函數(shù)的時候才將其復(fù)制到作用域鏈中;而另一個就是函數(shù)的活動對象,這個對象是在調(diào)用函數(shù)的時候才創(chuàng)建的。

在函數(shù)中訪問一個變量時,就會從作用域中搜索對應(yīng)名字的變量。

而當(dāng)函數(shù)執(zhí)行完畢后,函數(shù)的活動對象會被銷毀,而全局變量對象卻永遠(yuǎn)保存在內(nèi)存中。

但是,上面所說的都是普通函數(shù)的情況,對于閉包而言,又是另外一種情況:

以上面的 sayNameWithAge 函數(shù)為例:

function sayNameWithAge(age){
  return function(person){
    if(person.age == age){
      return person.name;
    }
  }
}
//創(chuàng)建函數(shù)
var sayName = sayNameWithAge(18);
//調(diào)用函數(shù)
var name = sayName({name:"Jack",age:18});
//解除對匿名函數(shù)的引用
sayName = null;

當(dāng)上面的 sayName 函數(shù)被調(diào)用的時候,產(chǎn)生的作用域鏈如下所示:

當(dāng)匿名函數(shù)被 return 后,它的作用域鏈被創(chuàng)建,并且包含了外部函數(shù)的活動對象和全局變量對象,這樣一來,這個匿名函數(shù)就可以訪問 sayNameWithAge 函數(shù)中定義的所有變量,也就是一個閉包。

這樣的閉包會存在一個問題,就是當(dāng) sayNameWithAge 函數(shù)執(zhí)行完畢的時候(JS 的垃圾處理機(jī)制大多是標(biāo)記清除),其活動對象被閉包所引用,所以活動對象并不會被銷毀,只有當(dāng)匿名函數(shù)被銷毀后,sayNameWithAge 的活動對象才會被銷毀,所以上面的最后一行解除對匿名函數(shù)的引用不僅是為了銷毀閉包的對象,也是為了銷毀外部函數(shù)的活動對象。所以,慎重使用閉包?。?!

關(guān)于閉包,還有一個需要注意的地方,就是在閉包中訪問其他函數(shù)的變量,實際上是因為閉包的作用域鏈中有指向其他函數(shù)的活動對象的引用,而不是閉包自身的活動對象中保存著這些變量??聪旅娴睦樱?/p>

function outer(){
  var result = new Array();
  for(var i = 0; i < 5; i ++){
    result[i] = function(){
      return i;
    };
  }
  return result;
}

按照設(shè)想,最后 outer 返回的數(shù)組各個項中的值應(yīng)該是與其下標(biāo)一致的。但是,最后的結(jié)果卻是每個項的值都是 5
不難想象,在上面的所有閉包的作用域鏈中,都有一個引用指向了 outer 的活動對象中的參數(shù) i,而且是指向同一個對象。

當(dāng) outer 函數(shù)執(zhí)行完畢的時候,i 的值是 5。也就是說,所有閉包中訪問 i 的時候取到的值都是 5

那么,我們可以通過另一種方法來實現(xiàn)預(yù)想的效果:

function outer(){
  var result = new Array();
  for(var i = 0; i < 5; i ++){
    result[i] = (fuction(index){
      return index;
    })(i);
  }
  return result;
}

這里我們?yōu)槟涿瘮?shù)定義一個參數(shù) index,并在每次循環(huán)中立即調(diào)用該函數(shù),將 i 的當(dāng)前值復(fù)制給參數(shù) index(注意 JS 中是按值傳遞),并將返回的 index 賦值給 result。

此外,閉包中需要注意的另一個問題是 this 對象。

this 對象在 JS 中是在函數(shù)運(yùn)行時基于函數(shù)的執(zhí)行環(huán)境綁定的。而匿名函數(shù)的執(zhí)行環(huán)境具有全局性,也就是說,在匿名函數(shù)中,this 對象通常指向 window。

var name = "Tom";
var person = {
  name : "Jack",
  sayName : function(){
    return (function(){
      return this.name;
    })();
  }
}
person.sayName(); //Tom

上面在閉包中訪問 this.name,其中的 this 對象并非取得自身或是 person 的 this 對象,而是指向 window。

如果需要在閉包中訪問外部函數(shù)的 this 對象,那么,可以在外部函數(shù)中定義一個變量,將 this 對象傳給該變量。

var name = "Tom";
var person = {
  name : "Jack",
  sayName : function(){
    var self = this;
    return (function(){
      return self.name;
    })();
  }
}
person.sayName(); //Jack



感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!

相關(guān)文章

  • JavaScript實現(xiàn)MIPS乘法模擬的方法

    JavaScript實現(xiàn)MIPS乘法模擬的方法

    這篇文章主要介紹了JavaScript實現(xiàn)MIPS乘法模擬的方法,實例分析了JavaScript實現(xiàn)MIPS乘法模擬的運(yùn)算技巧,需要的朋友可以參考下
    2015-04-04
  • JavaScript 對象合并的幾種方法小結(jié)

    JavaScript 對象合并的幾種方法小結(jié)

    本文主要介紹了JavaScript 對象合并的幾種方法小結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • JavaScript實現(xiàn)請求服務(wù)端接口方法詳解

    JavaScript實現(xiàn)請求服務(wù)端接口方法詳解

    這篇文章主要介紹了JavaScript實現(xiàn)請求服務(wù)端接口方法,JavaScript?中請求服務(wù)端接口的代碼實現(xiàn)可能會因為使用的方法而有所不同,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2023-01-01
  • javascript輕松控制表格列樣式的腳本代碼

    javascript輕松控制表格列樣式的腳本代碼

    javascript輕松控制表格列樣式的腳本代碼通過遍歷table表格元素并動態(tài)設(shè)置其class屬性,實現(xiàn)表格樣式動態(tài)控制的功能,需要的朋友可以參考一下
    2007-12-12
  • JavaScript隊列結(jié)構(gòu)Queue實現(xiàn)過程解析

    JavaScript隊列結(jié)構(gòu)Queue實現(xiàn)過程解析

    這篇文章主要介紹了JavaScript隊列結(jié)構(gòu)Queue實現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-03-03
  • 使用JavaScript保存文本文件到本地的兩種方法

    使用JavaScript保存文本文件到本地的兩種方法

    今天小編就為大家分享一篇關(guān)于使用JavaScript保存文本文件到本地的兩種方法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • js?Cannot?set?properties?of?null(setting?‘onclick‘)問題分析

    js?Cannot?set?properties?of?null(setting?‘onclick‘)問題分

    今天增加功能的時候,提示Uncaught?TypeError:?Cannot?set?properties?of?null?(setting?onclick)問題分享下,需要的朋友可以參考下
    2023-06-06
  • js實現(xiàn)聊天對話框

    js實現(xiàn)聊天對話框

    這篇文章主要為大家詳細(xì)介紹了js實現(xiàn)聊天對話框,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-02-02
  • JS首屏加載時間優(yōu)化的解決方法總結(jié)

    JS首屏加載時間優(yōu)化的解決方法總結(jié)

    首屏加載時間是一個衡量網(wǎng)頁性能和用戶體驗的關(guān)鍵指標(biāo),這個問題無論是在面試中還是在項目開發(fā)中都占有極其高的權(quán)重,本文為大家整理了幾種JS中優(yōu)化首屏加載時間的方法,希望對大家有所幫助
    2024-02-02
  • Taro UI框架開發(fā)小程序?qū)崿F(xiàn)左滑喜歡右滑不喜歡效果的示例代碼

    Taro UI框架開發(fā)小程序?qū)崿F(xiàn)左滑喜歡右滑不喜歡效果的示例代碼

    這篇文章主要介紹了Taro UI開發(fā)小程序?qū)崿F(xiàn)左滑喜歡右滑不喜歡效果,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-05-05

最新評論

太谷县| 平度市| 临高县| 阳城县| 丰镇市| 绥化市| 怀柔区| 临汾市| 西林县| 墨竹工卡县| 琼海市| 兴山县| 崇明县| 西林县| 河东区| 东平县| 仁布县| 玉田县| 兰考县| 于田县| 博白县| 应城市| 桦南县| 襄城县| 蒙山县| 南岸区| 甘南县| 尚志市| 蓝山县| 兖州市| 邢台市| 类乌齐县| 公主岭市| 葵青区| 苗栗市| 子长县| 江安县| 临湘市| 城步| 革吉县| 铁岭县|