成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

談?wù)凧avaScript的詞法環(huán)境和閉包(一)

AlphaWatch / 2818人閱讀

摘要:換句話說(shuō),定義在閉包中的函數(shù)可以記憶它被創(chuàng)建時(shí)候的環(huán)境。詞法環(huán)境的概念定義摘自百科。一個(gè)詞法環(huán)境由一個(gè)環(huán)境記錄項(xiàng)和可能為空的外部詞法環(huán)境引用構(gòu)成。中使用詞法環(huán)境管理靜態(tài)作用域。

一個(gè)資深的同事在我出發(fā)去面試前告誡我,問(wèn)JS知識(shí)點(diǎn)的時(shí)候千萬(wàn)別主動(dòng)提閉包,它就是一個(gè)坑?。】影。“?!

閉包確實(shí)是js的難點(diǎn)和重點(diǎn),其實(shí)也沒(méi)那么可怕,關(guān)鍵是機(jī)制的理解,可以和函數(shù)一起多帶帶拿出來(lái)說(shuō)說(shuō),其實(shí)關(guān)于閉包的解釋很多文章都寫得比較詳細(xì)了,這篇文章就作為自己學(xué)習(xí)過(guò)程的記錄吧。

閉包的概念

首先明確一下閉包的概念:

MDN (Mozilla Develop Network) 上的對(duì)閉包的定義:

閉包是指能夠訪問(wèn)自由變量的函數(shù) (變量在本地使用,但在閉包中定義)。換句話說(shuō),定義在閉包中的函數(shù)可以“記憶”它被創(chuàng)建時(shí)候的環(huán)境。

分析:

閉包由函數(shù)和與其相關(guān)的引用環(huán)境(詞法環(huán)境)的組合而成

閉包允許函數(shù)訪問(wèn)其引用環(huán)境(詞法環(huán)境)中的變量(又稱自由變量)

廣義上來(lái)說(shuō),所有JS的函數(shù)都可以稱為閉包,因?yàn)镴S函數(shù)在創(chuàng)建時(shí)保存了當(dāng)前的詞法環(huán)境

還是很拗口有木有,一臉懵逼的時(shí)候就應(yīng)該從基礎(chǔ)的概念開始找,所以我們來(lái)談?wù)勗~法環(huán)境。

詞法環(huán)境的概念

定義(摘自wiki百科)。

詞法環(huán)境是一個(gè)用于定義特定變量和函數(shù)標(biāo)識(shí)符在ECMAScript代碼的詞法嵌套結(jié)構(gòu)上關(guān)聯(lián)關(guān)系的規(guī)范類型。一個(gè)詞法環(huán)境由一個(gè)環(huán)境記錄項(xiàng)和可能為空的外部詞法環(huán)境引用構(gòu)成。

變量作用域

一般來(lái)說(shuō),在編程語(yǔ)言中都有變量作用域的概念,每個(gè)變量都有自己的生命周期和作用范圍。
作用域有兩種解析方式:

靜態(tài)作用域
又稱為詞法作用域,在編譯階就可以決定變量的引用,由程序定義的位置決定,和代碼執(zhí)行順序無(wú)關(guān),用嵌套的方式解析。

動(dòng)態(tài)作用域
在程序運(yùn)行時(shí)候,和代碼的執(zhí)行順序決定。用動(dòng)態(tài)棧動(dòng)態(tài)管理。

var x = 10;
function getX() {
    alert(x);
}
function foo() {
    var x = 20;
    getX();
}
foo();

在靜態(tài)作用域下:
全局作用域下有x, getX, foo三個(gè)變量,getXfoo都有自己的作用域。執(zhí)行foo函數(shù)的時(shí)候,getX()被執(zhí)行,但是getX的定義位置在全局作用域下的,取到的x是10,而不是20

在動(dòng)態(tài)作用域下:
運(yùn)行這段代碼時(shí),先把x=10getX、foo按順序壓棧,然后執(zhí)行foo函數(shù),在函數(shù)中把x=20壓棧,然后執(zhí)行getX(),此時(shí)距離棧頂最近的x值為20,因此alert的值也是20。

JavaScript使用的變量作用域是靜態(tài)作用域。JS中作用域簡(jiǎn)單分為兩部分:全局作用域和函數(shù)作用域。ES5中使用詞法環(huán)境管理靜態(tài)作用域。

詞法環(huán)境包含兩部分

環(huán)境記錄

形參

函數(shù)聲明

變量

其它...

對(duì)外部詞法環(huán)境的引用(outer)

環(huán)境記錄初始化

一段JS代碼執(zhí)行之前,會(huì)對(duì)環(huán)境記錄進(jìn)行初始化(聲明提前),即將函數(shù)的形參、函數(shù)聲明和變量先放入函數(shù)的環(huán)境記錄中,特別需要注意的是:

形參會(huì)在初始化的時(shí)候定義值,但是函數(shù)內(nèi)部定義的變量只聲明不定義(不賦值),這個(gè)需要用JS中的Hoisting機(jī)制來(lái)解釋,具體可以看這一篇文章:《理解 JavaScript(二):Scoping & Hoisting》。

以下面這段代碼為例,解析環(huán)境記錄初始化和代碼執(zhí)行的過(guò)程:

var x = 10;
function foo(y) {
    var z  = 30;
    function bar(q) {
        return x + y + z + q;
    }
    return bar;
}
var bar = foo(20);
bar(40);

step1:初始化全局環(huán)境

全局環(huán)境
環(huán)境記錄(record) foo:
x: undefined(聲明變量而非定義變量)
bar: undefined(聲明變量而非定義變量)
外部環(huán)境(outer) null

step2: 執(zhí)行x=10

全局環(huán)境
環(huán)境記錄(record) foo:
x: 10()
bar: undefined(聲明變量而非定義變量)
外部環(huán)境(outer) null

step3:執(zhí)行var bar = foo(20)語(yǔ)句之前,將foo函數(shù)的環(huán)境記錄初始化

foo 環(huán)境
環(huán)境記錄(record) y: 20(定義形參)
bar:
z: undefined(聲明變量而非定義變量)
外部環(huán)境(outer) 全局環(huán)境

step4:執(zhí)行var bar = foo(20)語(yǔ)句,變量bar接收f(shuō)oo函數(shù)中返回的bar函數(shù)

foo 環(huán)境
環(huán)境記錄(record) y: 20
bar:
z: 30(定義z)
外部環(huán)境(outer) 全局環(huán)境

step5:執(zhí)行bar函數(shù)之前,初始化bar的詞法環(huán)境

bar環(huán)境
環(huán)境記錄(record) q: 40(定義形參q)
外部環(huán)境(outer) foo環(huán)境

step6:在foo函數(shù)內(nèi)執(zhí)行bar函數(shù)

    x + y + z + q = 10 + 20 + 30 + 40 = 100 

其實(shí)說(shuō)了那么多,也是想強(qiáng)調(diào)一點(diǎn):形參的值在環(huán)境初始化的時(shí)候就賦值了!因此形參的作用之一就是保存外部變量的值!

一道閉包的面試題

查了一下關(guān)于閉包的面試題,用具體的例子說(shuō)明閉包的應(yīng)用場(chǎng)景。
最常見的答案來(lái)自于《JavaScript高級(jí)程序設(shè)計(jì)(第3版)》p181:

例子:

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

這個(gè)函數(shù)返回了長(zhǎng)度為10的函數(shù)數(shù)組,假設(shè)我們調(diào)用函數(shù)數(shù)組的第3個(gè)函數(shù),在控制臺(tái)中輸入creacteFunctions()[2](),即執(zhí)行函數(shù)數(shù)組里面的第三個(gè)函數(shù),creacteFunctions()返回函數(shù)數(shù)組,[2]是取第三個(gè)函數(shù)的引用,最后一個(gè)()是執(zhí)行第三個(gè)函數(shù),返回結(jié)果卻并不是預(yù)期的2,而是10.

因此,為了能夠讓閉包的行為符合預(yù)期,需要?jiǎng)?chuàng)建一個(gè)匿名函數(shù):

function creacteFunctions() {
    var result = new Array();
    for (var i = 0; i < 10; i++) {
        result[i] = function (num) {
            return function() {
                return num;
            }
        }(i);
    }
    return result;
}

此時(shí)在控制臺(tái)中輸入creacteFunctions()[2](),即執(zhí)行函數(shù)數(shù)組里面的第三個(gè)函數(shù),返回的就是預(yù)期中的2。
有了詞法環(huán)境的初始化過(guò)程,這里也就非常容易理解了。匿名函數(shù)的形參num保存了每次執(zhí)行的i的值。在function(num){...}(i)這個(gè)結(jié)構(gòu)中,i作為形參num的實(shí)際值執(zhí)行這個(gè)匿名函數(shù),因此每次循環(huán)中的num直接初始化為i的值。
為了更清楚的提取這部分結(jié)構(gòu),我們將匿名函數(shù)命名為helper:

var helper = function (num) {
    return function() {
        return num;
    }
}

用helper函數(shù)重寫第二段代碼:

var helper = function (num) {
    return function() {
        return num;
    }
}
function creacteFunctions() {
    var result = new Array();
    for (var i = 0; i < 10; i++) {
        result[i] = helper(i);
    }
    return result;
}

在控制臺(tái)中輸入creacteFunctions()[2](),輸出的也是預(yù)期中的2。

未完待續(xù)哦,閉包可以講的東西太多啦!

一句話總結(jié)

真正理解了作用域也就理解了閉包.

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

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

相關(guān)文章

  • 談?wù)?/em>eval另

    摘要:直到有一天關(guān)于閉包某一天,小伙伴們討論到說(shuō)關(guān)于閉包變量的問(wèn)題時(shí),君指出,如果一個(gè)函數(shù)沒(méi)有引用到其所處閉包的變量,那這個(gè)變量所指向的空間將被釋放。對(duì)于的引擎而言,如,,,無(wú)論閉包中是否包含,它們都不會(huì)釋放掉那些再也引用不到的變量。 之前在祼看ECMA262-5,在說(shuō)到eval的地方,死活看不明白為什么會(huì)有一節(jié)專門扯到Direct Call to Eval: A direct ca...

    ybak 評(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
  • JavaScript基礎(chǔ)系列---閉包及其應(yīng)用

    摘要:所以,有另一種說(shuō)法認(rèn)為閉包是由函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實(shí)體。所以本文中將以維基百科中的定義為準(zhǔn)即在計(jì)算機(jī)科學(xué)中,閉包,又稱詞法閉包或函數(shù)閉包,是引用了自由變量的函數(shù)。 閉包(closure)是JavaScript中一個(gè)神秘的概念,許多人都對(duì)它難以理解,我也一直處于似懂非懂的狀態(tài),前幾天深入了解了一下執(zhí)行環(huán)境以及作用域鏈,可戳查看詳情,而閉包與作用域及作用域鏈的關(guān)系密不可分,所...

    leoperfect 評(píng)論0 收藏0
  • 《你不知道javascript》筆記_作用域與閉包

    摘要:建筑的頂層代表全局作用域。實(shí)際的塊級(jí)作用域遠(yuǎn)不止如此塊級(jí)作用域函數(shù)作用域早期盛行的立即執(zhí)行函數(shù)就是為了形成塊級(jí)作用域,不污染全局。這便是閉包的特點(diǎn)吧經(jīng)典面試題下面的代碼輸出內(nèi)容答案?jìng)€(gè)如何處理能夠輸出閉包方式方式下一篇你不知道的筆記 下一篇:《你不知道的javascript》筆記_this 寫在前面 這一系列的筆記是在《javascript高級(jí)程序設(shè)計(jì)》讀書筆記系列的升華版本,旨在將零碎...

    galaxy_robot 評(píng)論0 收藏0
  • javascript閉包

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

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

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

0條評(píng)論

閱讀需要支付1元查看
<