国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

[學(xué)習(xí)筆記] JavaScript 閉包

sunsmell / 2616人閱讀

摘要:但是,必須強(qiáng)調(diào),閉包是一個(gè)運(yùn)行期概念。通過原型鏈可以實(shí)現(xiàn)繼承,而與閉包相關(guān)的就是作用域鏈。常理來(lái)說(shuō),一個(gè)函數(shù)執(zhí)行完畢,其執(zhí)行環(huán)境的作用域鏈會(huì)被銷毀。所以此時(shí),的作用域鏈雖然銷毀了,但是其活動(dòng)對(duì)象仍在內(nèi)存中。

學(xué)習(xí)Javascript閉包(Closure)
javascript的閉包
JavaScript 閉包深入理解(closure)
理解 Javascript 的閉包
JavaScript 中的閉包

看了《JS高級(jí)程序設(shè)計(jì)》和上面幾篇文章,小總結(jié)下JS閉包~

作為一個(gè)初學(xué)者,學(xué)習(xí)一個(gè)新的概念無(wú)非就是知道 “它是什么”、“什么原理”、“怎樣創(chuàng)建”、“有什么用”、“怎么用”,這篇文章就從這幾個(gè)角度介紹閉包,歡迎小伙伴們拍磚~

什么是閉包

上面幾篇文章,每一篇對(duì)閉包的定義都不相同,其實(shí)這真是一個(gè)很難用語(yǔ)言完美描述出來(lái)的東西。個(gè)人更喜歡阮一峰寫的:

  

閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)。

在JavaScript中,函數(shù)A內(nèi)部的局部變量不能被A以外的函數(shù)訪問到,只能被A內(nèi)部的子函數(shù)B訪問到,當(dāng)在函數(shù)A外調(diào)用函數(shù)B時(shí),便可通過B訪問A中局部變量,那么子函數(shù)B就是閉包。(注意,是子函數(shù)哦~)
這樣說(shuō)比較抽象,舉個(gè)栗子~

function outer() {

    var a = 100; // outer的局部變量

    function inner() { // 閉包
        console.log(a);
    }

    return inner; // 沒有這條語(yǔ)句,閉包起不到在outer外部訪問變量a的作用~
}
console.log(a); // 在外部直接訪問a出錯(cuò),Uncaught ReferenceError: a is not defined

var test = outer(); // outer運(yùn)行完返回inner,賦值給test
test(); // 100,執(zhí)行test(),相當(dāng)于執(zhí)行inner(),這樣就可以訪問到outer內(nèi)部的a了

司徒正美在blog中從另一個(gè)角度解釋了閉包:

  

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

閉包的原理

說(shuō)原理可能有些大,但這部分確實(shí)是要從內(nèi)部機(jī)制的角度,解釋下“為什么上面的栗子中通過inner就可以在outer外部訪問outer內(nèi)部的a”~

個(gè)人認(rèn)為在JS中,有兩個(gè)鏈很重要:原型鏈作用域鏈。通過 原型鏈 可以實(shí)現(xiàn)繼承,而與 閉包 相關(guān)的就是 作用域鏈。

還是上面的栗子,假設(shè)outer定義在全局作用域中

1  function outer() {

2     var a = 100; 

3     function inner() { 
4         console.log(a);
5     }

6     return inner; 
7  }

8  var test = outer(); 
9  test(); 

當(dāng)執(zhí)行到1處,outer函數(shù)定義,其作用域鏈中只有一個(gè)全局對(duì)象。
然后執(zhí)行8,運(yùn)行outer()。此時(shí),outer的作用域鏈中有兩個(gè)對(duì)象:outer的活動(dòng)對(duì)象-->全局對(duì)象。
運(yùn)行outer(),會(huì)執(zhí)行outer里面的3,定義inner(),此時(shí)inner的作用域鏈?zhǔn)牵?b>outer的活動(dòng)對(duì)象-->全局對(duì)象。
執(zhí)行9,其實(shí)就是執(zhí)行inner函數(shù),此時(shí)其作用域鏈?zhǔn)牵?b>inner的活動(dòng)對(duì)象-->outer的活動(dòng)對(duì)象-->全局對(duì)象。

因?yàn)閕nner的作用域鏈中有outer的活動(dòng)對(duì)象,所以它可以訪問到outer的局部變量a。

常理來(lái)說(shuō),一個(gè)函數(shù)執(zhí)行完畢,其執(zhí)行環(huán)境的作用域鏈會(huì)被銷毀。但是outer執(zhí)行完畢后,其活動(dòng)對(duì)象仍然保留在內(nèi)存中,因?yàn)閕nner的作用域鏈仍在引用著這個(gè)活動(dòng)對(duì)象。所以此時(shí),outer的作用域鏈雖然銷毀了,但是其活動(dòng)對(duì)象仍在內(nèi)存中。直到test執(zhí)行完畢,outer的活動(dòng)對(duì)象才被銷毀。

也正因?yàn)槿绱耍?strong>閉包只能取得包含函數(shù)中任何變量的最后一個(gè)值,即包含函數(shù)執(zhí)行完畢時(shí)變量的值。改改之前的栗子~

 function outer() {

    var a = 100; 

    function inner() { 
        console.log(a);
    } 

    a = a + 50; // 改變a的值

    return inner; 
}

var test = outer(); 
test(); // 150,取得的a是150,而不是100

正是因?yàn)樽饔糜蜴?,只能里面的訪問外面的,外面的不能訪問里面的。也是基于作用域鏈,聰明的大師們想出了閉包,使得外面的可以訪問里面的。掌握作用域鏈很關(guān)鍵啊~

創(chuàng)建閉包的方式

創(chuàng)建閉包最常見的方式就是在一個(gè)函數(shù)里面創(chuàng)建一個(gè)函數(shù),之前舉得栗子就是。

司徒正美大神給出了3種閉包實(shí)現(xiàn):

with(obj){
    //這里是對(duì)象閉包
}
(function(){
    //函數(shù)閉包
 })();
try{
   //...
} catch(e) {
   //catch閉包 但I(xiàn)E里不行
}
閉包的作用

1. 在函數(shù)外面讀取函數(shù)的局部變量
前面一直在說(shuō)這個(gè)事兒~

2. 在內(nèi)存中維持一個(gè)變量

function outer() {

    var a = 100; 

    function inner() { 
        console.log(a++);
    } 

    return inner; 
}

var test = outer(); 
test(); // 100
test(); // 101
test(); // 102

栗子中a一直在內(nèi)存中,每執(zhí)行一次test(),輸出值加1。因?yàn)?b>test在全局執(zhí)行環(huán)境中,所以a一直在內(nèi)存中,如果test在其他執(zhí)行環(huán)境中,當(dāng)這個(gè)執(zhí)行執(zhí)行環(huán)境銷毀的時(shí)候,a就不會(huì)再在內(nèi)存中了。

3. 實(shí)現(xiàn)面向?qū)ο笾械膶?duì)象
javascript并沒有提供類這樣的機(jī)制,但是可以通過閉包來(lái)模擬類的機(jī)制。把父函數(shù)當(dāng)作對(duì)象(object)使用,把閉包當(dāng)作它的公用方法(Public Method),把內(nèi)部變量當(dāng)作它的私有屬性(private value)。

function Person(){
    var name = "XiaoMing";

    return {
        setName : function(theName){
            name = theName;
        },

        getName : function(){
            return name;
        }
    };
}
var person = new Person();
console.log(person.name); // undefined
console.log(person.getName()); // XiaoMing
幾個(gè)閉包示例

參考的這幾篇文章基本都給出了閉包示例,悄悄摘選司徒正美大神的幾個(gè)放到這里~

//*************閉包uniqueID*************

uniqueID = (function(){

    var id = 0; 
    return function() { 
        return id++; // 返回,自加
    };  
})(); 

document.writeln(uniqueID()); //0
document.writeln(uniqueID()); //1
document.writeln(uniqueID()); //2
document.writeln(uniqueID()); //3
document.writeln(uniqueID()); //4
//*************閉包階乘*************

var a = (function(n) {
    if (n<1) { 
        alert("invalid arguments"); 
        return 0; 
    }
    if(n==1) { 
        return 1; 
    }
    else { 
        return n * arguments.callee(n-1); 
    }
})(4);

document.writeln(a);
//***********實(shí)現(xiàn)面向?qū)ο笾械膶?duì)象***********

function Person(){
    var name = "XiaoMing";

    return {
        setName : function(theName){
            name = theName;
        },

        getName : function(){
            return name;
        }
    };
}
var person = new Person();
console.log(person.name); // undefined
console.log(person.getName()); // XiaoMing
//***********避免 Lift 效應(yīng)***********

var tasks = [];
for (var i = 0; i < 5; i++) {
    // 注意有一層額外的閉包
    tasks[tasks.length] = (function (i) {
        return function () {
            console.log("Current cursor is at " + i);
        };
    })(i);
}

var len = tasks.length;
while (len--) {
    tasks[len]();
}

運(yùn)行結(jié)果:

Current cursor is at 4
Current cursor is at 3
Current cursor is at 2
Current cursor is at 1
Current cursor is at 0

補(bǔ)充:Lift效應(yīng)

var tasks = [];
for (var i = 0; i < 5; i++) {
    tasks[tasks.length] = function () {
        console.log("Current cursor is at " + i);
    };
}

var len = tasks.length;
while (len--) {
    tasks[len]();
}

上面這段代碼輸出5

Current cursor is at 5

這一現(xiàn)象稱為 Lift效應(yīng)。原因在于

  

在引用函數(shù)外部變量時(shí),函數(shù)執(zhí)行時(shí)外部變量的值由運(yùn)行時(shí)決定而非定義時(shí)

實(shí)際編程的時(shí)候,很容易遇見lift效應(yīng),加一層閉包就可以解決哦~

需注意的問題

由于閉包會(huì)使得函數(shù)中的變量都被保存在內(nèi)存中,內(nèi)存消耗很大,所以不能濫用閉包,否則會(huì)造成網(wǎng)頁(yè)的性能問題,在IE中可能導(dǎo)致內(nèi)存泄露。解決方法是,在退出函數(shù)之前,將不使用的局部變量全部刪除。
如果有非常龐大的對(duì)象,且預(yù)計(jì)會(huì)在老舊的引擎中執(zhí)行,則使用閉包時(shí),注意將閉包不需要的對(duì)象置為空引用。

這是我對(duì)于閉包學(xué)習(xí)的總結(jié),錯(cuò)誤和不足歡迎大家指正~

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/85744.html

相關(guān)文章

  • 學(xué)習(xí)筆記JavaScript 閉包是怎么通過作用域鏈霸占更多內(nèi)存的?

    摘要:閉包是怎么通過作用域鏈霸占更多內(nèi)存的本文是作者學(xué)習(xí)高級(jí)程序設(shè)計(jì)第一小節(jié)的一點(diǎn)個(gè)人理解,詳細(xì)教程請(qǐng)參考原教材。函數(shù)執(zhí)行過程創(chuàng)建了一個(gè)函數(shù)的活動(dòng)對(duì)象,作用域鏈的最前端指向這個(gè)對(duì)象。函數(shù)執(zhí)行完畢返回值后執(zhí)行環(huán)境作用域鏈和活動(dòng)對(duì)象一并銷毀。 JavaScript 閉包是怎么通過作用域鏈霸占更多內(nèi)存的? 本文是作者學(xué)習(xí)《JavaScript 高級(jí)程序設(shè)計(jì)》7.2第一小節(jié)的一點(diǎn)個(gè)人理解,詳細(xì)教程請(qǐng)...

    HmyBmny 評(píng)論0 收藏0
  • Js學(xué)習(xí)筆記閉包

    摘要:一前言這個(gè)周末,注意力都在學(xué)習(xí)基礎(chǔ)知識(shí)上面,剛好看到了閉包這個(gè)神圣的東西,所以打算把這兩天學(xué)到的總結(jié)下來(lái),算是鞏固自己所學(xué)。因此要注意閉包的使用,否則會(huì)導(dǎo)致性能問題。五總結(jié)閉包的作用能夠讀取其他函數(shù)內(nèi)部變量。 # 一、前言 這個(gè)周末,注意力都在學(xué)習(xí)基礎(chǔ)Js知識(shí)上面,剛好看到了閉包這個(gè)神圣的東西,所以打算把這兩天學(xué)到的總結(jié)下來(lái),算是鞏固自己所學(xué)。也可能有些不正確的地方,也請(qǐng)大家看到了,麻...

    Crazy_Coder 評(píng)論0 收藏0
  • JS學(xué)習(xí)筆記(第7章)(函數(shù)表達(dá)式)

    摘要:遞歸閉包模仿塊級(jí)作用域私有變量小結(jié)在編程中,使用函數(shù)表達(dá)式可以無(wú)需對(duì)函數(shù)命名,從而實(shí)現(xiàn)動(dòng)態(tài)編程。匿名函數(shù)也稱為拉姆達(dá)函數(shù)。函數(shù)聲明要求有名字,但函數(shù)表達(dá)式不需要。中的函數(shù)表達(dá)式和閉包都是極其有用的特性,利用它們可以實(shí)現(xiàn)很多功能。 1、遞歸 2、閉包 3、模仿塊級(jí)作用域 4、私有變量 5、小結(jié) 在JavaScript編程中,使用函數(shù)表達(dá)式可以無(wú)需對(duì)函數(shù)命名,從而實(shí)現(xiàn)動(dòng)態(tài)編程。匿名函數(shù)也稱...

    xiaokai 評(píng)論0 收藏0
  • JS筆記

    摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來(lái)降低異步編程的復(fù)雜性。異步編程入門的全稱是前端經(jīng)典面試題從輸入到頁(yè)面加載發(fā)生了什么這是一篇開發(fā)的科普類文章,涉及到優(yōu)化等多個(gè)方面。 TypeScript 入門教程 從 JavaScript 程序員的角度總結(jié)思考,循序漸進(jìn)的理解 TypeScript。 網(wǎng)絡(luò)基礎(chǔ)知識(shí)之 HTTP 協(xié)議 詳細(xì)介紹 HTT...

    rottengeek 評(píng)論0 收藏0
  • 重學(xué)前端學(xué)習(xí)筆記(十八)--JavaScript閉包和執(zhí)行上下文

    摘要:申明與賦值立即執(zhí)行的函數(shù)表達(dá)式,通過創(chuàng)建一個(gè)函數(shù),并且立即執(zhí)行,來(lái)構(gòu)造一個(gè)新的域,從而控制的范圍。函數(shù)接受一個(gè)的形參,該參數(shù)是一個(gè)對(duì)象引用,并執(zhí)行了。在最新的標(biāo)準(zhǔn)中,引入了一個(gè)新概念。 筆記說(shuō)明 重學(xué)前端是程劭非(winter)【前手機(jī)淘寶前端負(fù)責(zé)人】在極客時(shí)間開的一個(gè)專欄,每天10分鐘,重構(gòu)你的前端知識(shí)體系,筆者主要整理學(xué)習(xí)過程的一些要點(diǎn)筆記以及感悟,完整的可以加入winter的專欄...

    silencezwm 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<