亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

javascript閉包

binaryTree / 868人閱讀

摘要:閉包的定義閉包是函數(shù)和聲明該函數(shù)的詞法作用域的組合。上面的和都是閉包。然而在一個(gè)閉包內(nèi)對(duì)變量的修改,不會(huì)影響到另一個(gè)閉包中的變量。原因是賦值給的是閉包。由于循環(huán)在事件觸發(fā)之前早已執(zhí)行完畢,變量被三個(gè)閉包共享已經(jīng)變成了。

閉包的定義:
閉包是函數(shù)和聲明該函數(shù)的詞法作用域的組合。

先看如下例子:

function makeFn(){
    var name = "Mirror";
    function showName(){
        alert(name)
    }
    
    return showName;
}

var myFn = makeFn();
myFn();  // "Mirror"

javascript 中的函數(shù)會(huì)形成閉包。閉包是由函數(shù)以及創(chuàng)建該函數(shù)的詞法環(huán)境組合組成。這個(gè)環(huán)境包含了這個(gè)閉包創(chuàng)建時(shí)所能訪問(wèn)的所有局部變量。在以上的例子中,myFn是執(zhí)行makeFn時(shí)創(chuàng)建的showName函數(shù)實(shí)例的引用,而showName實(shí)例仍可訪問(wèn)其詞法作用域中的變量,既可以訪問(wèn)到name。 由此,當(dāng)myFn 被調(diào)用時(shí),name仍可被訪問(wèn)。

再看一個(gè)更有意思的例子:

function makeAdder(x){
    return function( y ){
        return x + y 
    }
}

var add5 = makeAdder( 5 );    
var add10 = makeAdder( 10 );
console.log( add5(2) )  // 7 
console.log( add10(2) )   // 12

以上示例中,我們定義了makeAdder(x) 函數(shù),它接收一個(gè)參數(shù)x ,并返回一個(gè)新的函數(shù)。返回的函數(shù)接受一個(gè)參數(shù)y,并返回 x+y的值。

本質(zhì)上講,makeAdder 是一個(gè)工廠函數(shù) -- 它創(chuàng)建了將指定的值和它的參數(shù)相加求和的函數(shù)。上面的add5add10都是閉包。它們共享相同的函數(shù)定義,但是保存了不同的詞法環(huán)境。在add5的環(huán)境中,x為5,而在add10中,x則是10。

實(shí)用的閉包:

閉包允許將函數(shù)與其所操作的某些數(shù)據(jù)(環(huán)境)關(guān)聯(lián)起來(lái)。這顯然類似于面向?qū)ο缶幊?。在面向?qū)ο缶幊讨?,?duì)象允許我們將某些數(shù)據(jù)(對(duì)象的屬性)與一個(gè)或者多個(gè)方法相關(guān)聯(lián)。

通常,使用只有一個(gè)方法的對(duì)象的地方都可以使用閉包。

假如,我們想在頁(yè)面上添加一些可以調(diào)整字號(hào)的按鈕。一種方法是以像素為單位指定 body 元素的 font-size,然后通過(guò)相對(duì)的 em 單位設(shè)置頁(yè)面中其它元素(例如header)的字號(hào):




    
    
    


    

h1 標(biāo)簽

h2 標(biāo)簽

用閉包模擬私有方法:

私有方法不僅僅有利于限制對(duì)代碼的訪問(wèn),還提供了管理全局命名空間的強(qiáng)大能力,避免非核心的方法弄亂了代碼的公共接口部分。

var Counter = ( function(){
    var privateCounter = 0;
    function changeBy(val){
        privateCounter += val
    };
    
    return {
        add:function(){
            changeBy(1);
            return privateCounter;
        },
        decrease:function(){
            changeBy(-1);
            return privateCounter;
        },
        value:function(){
            return privateCounter;
        }
    }
    
})()

以上示例中我們只創(chuàng)建了一個(gè)詞法環(huán)境,為三個(gè)函數(shù)所共享:Counter.add、 Counter.decreaseCounter.value

該共享環(huán)境創(chuàng)建一個(gè)立即執(zhí)行的匿名函數(shù)體內(nèi)。這個(gè)環(huán)境中包含兩個(gè)私有項(xiàng):privateCounter的變量和changeBy的函數(shù)。這兩項(xiàng)都無(wú)法在這個(gè)匿名函數(shù)外直接訪問(wèn)。必須通過(guò)匿名函數(shù)返回的三個(gè)公共函數(shù)訪問(wèn)。

這三個(gè)公共函數(shù)是共享同一個(gè)環(huán)境的閉包。多虧javascript的詞法作用域,它們都可以訪問(wèn)privateCounter變量和changeBy函數(shù)。

應(yīng)該注意到我們定義了一個(gè)匿名函數(shù),用來(lái)創(chuàng)建計(jì)算器。立即執(zhí)行函數(shù)將他的值賦給了變量Counter。我們也可以將這個(gè)函數(shù)存儲(chǔ)在另一個(gè)變量makeCounter中,并用它來(lái)創(chuàng)建多個(gè)計(jì)數(shù)器。
var makeCounter = function(){
    var privateCounter = 0;
    var changeBy = function(val){
        privateCounter += val
    };
    return {
        add:function(){
            changeBy(1)
            return privateCounter
        },
        decrease:function(){
             changeBy(-1)
             return privateCounter
        },
        value:function(){
            return privateCounter
        }
    }
}


var Counter1 = makeCounter();
var Counter2 = makeCounter();
Counter1.add() // 1
Counter2.decrease() // -1

兩個(gè)計(jì)數(shù)器Counter1Counter2都引用自己詞法作用域內(nèi)的變量privateCounter。每次調(diào)用其中一個(gè)計(jì)數(shù)器時(shí),通過(guò)改變這個(gè)變量的值,會(huì)改變這個(gè)閉包的詞法環(huán)境。然而在一個(gè)閉包內(nèi)對(duì)變量的修改,不會(huì)影響到另一個(gè)閉包中的變量。

以這種方式使用閉包,提供了許多面向?qū)ο缶幊滔嚓P(guān)的好處——特別是數(shù)據(jù)隱藏和封裝。
在循環(huán)中創(chuàng)建閉包:一個(gè)常見(jiàn)的錯(cuò)誤

在ECMAScript2015引入let關(guān)鍵字以前,在循環(huán)中有一個(gè)常見(jiàn)的閉包創(chuàng)建問(wèn)題。如下:





運(yùn)行以上代碼,會(huì)發(fā)現(xiàn)沒(méi)有達(dá)到想要的結(jié)果。無(wú)論點(diǎn)擊哪個(gè)按鈕,彈窗提示的都是第3個(gè)按鈕。

原因是賦值給onclick的是閉包。三個(gè)閉包在循環(huán)中被創(chuàng)建,但是他們共享同一個(gè)詞法作用域,在這個(gè)作用域中存在一個(gè)變量i。當(dāng)onclick的回調(diào)執(zhí)行時(shí),i的值被決定。由于循環(huán)在事件觸發(fā)之前早已執(zhí)行完畢,變量i(被三個(gè)閉包共享)已經(jīng)變成了"3"。

解決這個(gè)問(wèn)題的一種方案是使用跟多的閉包:特別是使用前面所述的函數(shù)工廠:





這段代碼可以如我們所期望的那樣工作。所有的回調(diào)不再共享同一個(gè)環(huán)境,clickCallback函數(shù)為每一個(gè)回調(diào)創(chuàng)建一個(gè)新的詞法環(huán)境。在這些環(huán)境中。x指向循環(huán)中的i。

另一種方法實(shí)現(xiàn)了匿名閉包:






避免使用過(guò)多的閉包,可以用let關(guān)鍵詞:





 

這個(gè)例子使用的是let而不是var,因此每個(gè)閉包都綁定了塊作用域的變量,這意味著不再需要額外的閉包。

性能考量

如果不是某些特定的任務(wù)需要使用閉包,在其他函數(shù)中創(chuàng)建函數(shù)是不明智的,因?yàn)殚]包在處理速度和內(nèi)存消耗方面對(duì)腳本性能具有負(fù)面影響。

例如,在創(chuàng)建新的對(duì)象或者類時(shí),方法通常應(yīng)該關(guān)聯(lián)于對(duì)象的原型,而不是定義到對(duì)象的構(gòu)造器中。原因是這將導(dǎo)致每次構(gòu)造器被調(diào)用時(shí),方法都會(huì)被重新賦值一次(也就是,每個(gè)對(duì)象的創(chuàng)建)。

考慮一下示例:

function MyObject( name , message ){
    this.name = name;
    this.message = message.toString();
    this.getName = function(){
        return this.name;
    };
    this.getMessage = function(){
        return this.message
    };
}
上面的代碼并未利用到閉包的好處,可以修改成如下:
function MyObject(name, message) {
  this.name = name.toString();
  this.message = message.toString();
}
MyObject.prototype = {
  getName: function() {
    return this.name;
  },
  getMessage: function() {
    return this.message;
  }
};
不建議重新定義原型。可改成如下例子:
function MyObject(name, message) {
  this.name = name.toString();
  this.message = message.toString();
}
MyObject.prototype.getName = function() {
  return this.name;
};
MyObject.prototype.getMessage = function() {
  return this.message;
};

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/95458.html

相關(guān)文章

  • Javascript閉包入門(譯文)

    摘要:也許最好的理解是閉包總是在進(jìn)入某個(gè)函數(shù)的時(shí)候被創(chuàng)建,而局部變量是被加入到這個(gè)閉包中。在函數(shù)內(nèi)部的函數(shù)的內(nèi)部聲明函數(shù)是可以的可以獲得不止一個(gè)層級(jí)的閉包。 前言 總括 :這篇文章使用有效的javascript代碼向程序員們解釋了閉包,大牛和功能型程序員請(qǐng)自行忽略。 譯者 :文章寫(xiě)在2006年,可直到翻譯的21小時(shí)之前作者還在完善這篇文章,在Stackoverflow的How do Java...

    Fourierr 評(píng)論0 收藏0
  • 理解Javascript閉包

    摘要:但是閉包也不是什么復(fù)雜到不可理解的東西,簡(jiǎn)而言之,閉包就是閉包就是函數(shù)的局部變量集合,只是這些局部變量在函數(shù)返回后會(huì)繼續(xù)存在??上У氖?,并沒(méi)有提供相關(guān)的成員和方法來(lái)訪問(wèn)閉包中的局部變量。 (收藏自 技術(shù)狂) 前言:還是一篇入門文章。Javascript中有幾個(gè)非常重要的語(yǔ)言特性——對(duì)象、原型繼承、閉包。其中閉包 對(duì)于那些使用傳統(tǒng)靜態(tài)語(yǔ)言C/C++的程序員來(lái)說(shuō)是一個(gè)新的語(yǔ)言特性。本文將...

    dayday_up 評(píng)論0 收藏0
  • JavaScript閉包,只學(xué)這篇就夠了

    摘要:當(dāng)在中調(diào)用匿名函數(shù)時(shí),它們用的都是同一個(gè)閉包,而且在這個(gè)閉包中使用了和的當(dāng)前值的值為因?yàn)檠h(huán)已經(jīng)結(jié)束,的值為。最好將閉包當(dāng)作是一個(gè)函數(shù)的入口創(chuàng)建的,而局部變量是被添加進(jìn)這個(gè)閉包的。 閉包不是魔法 這篇文章使用一些簡(jiǎn)單的代碼例子來(lái)解釋JavaScript閉包的概念,即使新手也可以輕松參透閉包的含義。 其實(shí)只要理解了核心概念,閉包并不是那么的難于理解。但是,網(wǎng)上充斥了太多學(xué)術(shù)性的文章,對(duì)于...

    CoderBear 評(píng)論0 收藏0
  • JavaScript深入之閉包

    摘要:深入系列第八篇,介紹理論上的閉包和實(shí)踐上的閉包,以及從作用域鏈的角度解析經(jīng)典的閉包題。定義對(duì)閉包的定義為閉包是指那些能夠訪問(wèn)自由變量的函數(shù)。 JavaScript深入系列第八篇,介紹理論上的閉包和實(shí)踐上的閉包,以及從作用域鏈的角度解析經(jīng)典的閉包題。 定義 MDN 對(duì)閉包的定義為: 閉包是指那些能夠訪問(wèn)自由變量的函數(shù)。 那什么是自由變量呢? 自由變量是指在函數(shù)中使用的,但既不是函數(shù)參數(shù)也...

    caige 評(píng)論0 收藏0
  • 還擔(dān)心面試官問(wèn)閉包

    摘要:一言以蔽之,閉包,你就得掌握。當(dāng)函數(shù)記住并訪問(wèn)所在的詞法作用域,閉包就產(chǎn)生了。所以閉包才會(huì)得以實(shí)現(xiàn)。從技術(shù)上講,這就是閉包。執(zhí)行后,他的內(nèi)部作用域并不會(huì)消失,函數(shù)依然保持有作用域的閉包。 網(wǎng)上總結(jié)閉包的文章已經(jīng)爛大街了,不敢說(shuō)筆者這篇文章多么多么xxx,只是個(gè)人理解總結(jié)。各位看官瞅瞅就好,大神還希望多多指正。此篇文章總結(jié)與《JavaScript忍者秘籍》 《你不知道的JavaScri...

    tinyq 評(píng)論0 收藏0
  • [學(xué)習(xí)筆記](méi) JavaScript 閉包

    摘要:但是,必須強(qiáng)調(diào),閉包是一個(gè)運(yùn)行期概念。通過(guò)原型鏈可以實(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 ...

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

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

0條評(píng)論

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