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

資訊專欄INFORMATION COLUMN

ES5之執(zhí)行環(huán)境和作用域(變量的生命周期)

wemall / 3283人閱讀

摘要:作用域鏈的用途,是保證對(duì)執(zhí)行環(huán)境,有權(quán)訪問的所有變量和函數(shù)的有序訪問。全局執(zhí)行環(huán)境的變量對(duì)象,始終是作用域鏈中的最后一個(gè)對(duì)象。每個(gè)環(huán)境都可以向上搜索作用域鏈,以查詢變量和函數(shù)名。

前言:最近在細(xì)讀Javascript高級(jí)程序設(shè)計(jì),對(duì)于我而言,中文版,書中很多地方一筆帶過,所以用自己所理解的,嘗試細(xì)致解讀下。如有紕漏或錯(cuò)誤,會(huì)非常感謝您的指出。文中絕大部分內(nèi)容引用自《JavaScript高級(jí)程序設(shè)計(jì)第三版》。

執(zhí)行環(huán)境(execution context)

執(zhí)行環(huán)境(execution context,為了簡(jiǎn)單起見,有時(shí)也成為環(huán)境)是JavaScript中最為重要的一個(gè)概念。

執(zhí)行環(huán)境,定義了變量或函數(shù)有權(quán)訪問其他數(shù)據(jù),且決定了它們各自的行為。

每個(gè)執(zhí)行環(huán)境都有一個(gè)與之關(guān)聯(lián)的變量對(duì)象(variable object),環(huán)境中定義的所有變量和函數(shù)都保存在這個(gè)對(duì)象中。

雖然我們編寫的代碼無法訪問這個(gè)對(duì)象,但解析器在處理數(shù)據(jù)時(shí)會(huì)在后臺(tái)使用它。

全局執(zhí)行環(huán)境時(shí)最外圍的一個(gè)執(zhí)行環(huán)境。

根據(jù)ECMAScript實(shí)現(xiàn)所在的宿主環(huán)境不同,表示執(zhí)行環(huán)境的對(duì)象也不一樣。

在Web瀏覽器中,全局執(zhí)行環(huán)境被認(rèn)為是window對(duì)象,因此所有全局變量和函數(shù)都是作為window對(duì)象的屬性和方法創(chuàng)建的。

(變量的生命周期),某個(gè)執(zhí)行環(huán)境中的所有代碼執(zhí)行完畢后,該環(huán)境被銷毀,保存在其中的所有變量和函數(shù)定義也隨之銷毀)

全局執(zhí)行環(huán)境直到應(yīng)用程序退出——例如關(guān)閉網(wǎng)頁(yè)或?yàn)g覽器時(shí)才會(huì)被銷毀。

每個(gè)函數(shù)都有自己的執(zhí)行環(huán)境。當(dāng)執(zhí)行流進(jìn)入一個(gè)函數(shù)時(shí),函數(shù)的環(huán)境就會(huì)被推入一個(gè)環(huán)境棧中。在函數(shù)執(zhí)行之后,棧將其環(huán)境彈出,把控制權(quán)返回給之前的執(zhí)行環(huán)境。ECMAScript程序中的執(zhí)行流正是由這個(gè)方便的機(jī)制控制著。

作用域鏈(scope chain)

當(dāng)代碼在一個(gè)環(huán)境中執(zhí)行時(shí),會(huì)創(chuàng)建變量對(duì)象的一個(gè)作用域鏈(scope chain)。
作用域鏈的用途,是保證對(duì)執(zhí)行環(huán)境,有權(quán)訪問的所有變量和函數(shù)的有序訪問。

作用域鏈的前端,始終都是當(dāng)前執(zhí)行的代碼所在環(huán)境的變量對(duì)象。(也可以理解為“就近原則”)。

如果這個(gè)環(huán)境是函數(shù),則將其活動(dòng)對(duì)象(activation object)作為變量對(duì)象。

函數(shù)執(zhí)行環(huán)境中的活動(dòng)對(duì)象在最開始時(shí),只包含一個(gè)變量,即arguments對(duì)象(這個(gè)對(duì)象在全局環(huán)境中是不存在的)作為變量對(duì)象。

作用域鏈中的下一個(gè)變量對(duì)象來自包含(外部)環(huán)境,而再下一個(gè)變量對(duì)象則來自下一個(gè)包含環(huán)境,這樣,一直延續(xù)到全局執(zhí)行環(huán)境。

全局執(zhí)行環(huán)境的變量對(duì)象,始終是作用域鏈中的最后一個(gè)對(duì)象。

標(biāo)識(shí)符解析是沿著作用域鏈一級(jí)一級(jí)地搜索標(biāo)識(shí)標(biāo)識(shí)符的過程。
搜索過程始終從作用域鏈的前端開始,然后逐級(jí)向后回溯,直至找到標(biāo)識(shí)符為止(如果找不到標(biāo)識(shí)符,通過會(huì)導(dǎo)致錯(cuò)誤發(fā)生)。

var color = "blue";

function changeColor() {
    if(color === "blue") {
        color = "red";
    } else {
        color = "blue";
    }
}

changeColor();

console.log("Color is now " + color); // "color is now red"

在這個(gè)簡(jiǎn)單的例子中,函數(shù)changeColor()的作用域鏈包含兩個(gè)對(duì)象:

它自己的變量對(duì)象(其中定義著arguments對(duì)象)和全局環(huán)境的變量對(duì)象。

可以在函數(shù)內(nèi)部訪問變量color,就是因?yàn)榭梢栽谶@個(gè)作用域鏈中找到它。

此外,在局部作用中定義的變量可以在局部環(huán)境中與全局變量互換使用。

var color = "blue";

function changeColor() {
    var anotherColor = "red";

    function swapColors(){

        //這里可以訪問color、anotherColor和tempColor
        var tempColor = anotherColor;
        anotherColor = color;
        color = tempColor;
    }

    //這里可以訪問color和anotherColor,但不能訪問tempColor
    swapColors();
}

//這里只能訪問color
changeColor();

以上代碼,涉及3個(gè)執(zhí)行環(huán)境:

全局環(huán)境(在web瀏覽器中就是window)

函數(shù)changeColor()的局部環(huán)境

函數(shù)swapColors()的局部局部

全局環(huán)境中有一個(gè)變量color和一個(gè)函數(shù)changeColor()。changeColor()的局部環(huán)境中有一個(gè)名為anotherColor的變量和一個(gè)名為swapColors()的函數(shù),但它也可以訪問全局環(huán)境中的變量color。swapColors()的局部環(huán)境中有一個(gè)變量tempColor,該變量只能在這個(gè)環(huán)境中訪問到。

無論全局環(huán)境還是changeColor()的局部環(huán)境都無權(quán)訪問tempColor。

然而,在swapColors()內(nèi)部,則可以訪問其他兩個(gè)環(huán)境中的變量,因?yàn)槟莾蓚€(gè)環(huán)境是它的父執(zhí)行環(huán)境。

      
 window, color, changeColor()
            |
    anotherColor, swapColors()
                    |
                tempColor

內(nèi)部環(huán)境可以通過作用域鏈訪問所有的外部環(huán)境,但外部環(huán)境不能訪問內(nèi)部環(huán)境中的任何變量和函數(shù)。

這些環(huán)境之間的聯(lián)系是線性、有次序的。

每個(gè)環(huán)境都可以向上搜索作用域鏈,以查詢變量和函數(shù)名。但是,任何環(huán)境都不能通過向下搜索作用域鏈而進(jìn)入另一個(gè)執(zhí)行環(huán)境。

函數(shù)參數(shù)也被當(dāng)做變量來對(duì)待,因此其訪問規(guī)則與執(zhí)行環(huán)境中的其他變量相同。

沒有塊級(jí)作用域(ES5中沒有)

JavaScript沒有塊級(jí)作用域經(jīng)常會(huì)導(dǎo)致理解上的困惑。
在其他類C的語言中,由花括號(hào)封閉的代碼塊都有自己的作用域(如果用ECMAScript的話來講,就是它們自己的執(zhí)行環(huán)境),因而支持根據(jù)條件來定義變量。

if(true) {
    var color = "blue";
}

console.log(color); //"blue"

這里是在有一個(gè)if語句中定義了變量color。
如果是在C、C++或Java中,color會(huì)在if語句執(zhí)行完畢后被銷毀。
但在JavaScript中,if語句中的變量聲明會(huì)將變量添加當(dāng)前的執(zhí)行環(huán)境(在這里是全局環(huán)境window)中。

在使用for語句時(shí)尤其要牢記這一差異。

for(var i = 0; i < 10; i++) {
    console.log(i); // 0,1,2,3,4,5,6,7,8,9
}

/*
//等價(jià)于
var i;

for(i = 0; i < 10; i++) {
    console.log(i);
}

*/

console.log(i); //10

對(duì)于有塊級(jí)作用域的語言來說,for語句初始化變量的表達(dá)式所定義的變量,只會(huì)存在于循壞的環(huán)境之中。而對(duì)于JavaScript來說,由for語句創(chuàng)建的變量i即使在for循環(huán)結(jié)束之后,也依舊會(huì)存在于循壞外部的執(zhí)行環(huán)境中。

聲明變量

使用var聲明的變量會(huì)自動(dòng)被添加到最接近的環(huán)境中,在函數(shù)內(nèi)部,最接近的環(huán)境就是函數(shù)的局部環(huán)境。

如果初始化變量時(shí)沒有使用var聲明,該變量會(huì)自動(dòng)被添加到全局作用域。

function add(num1, num2) {
    var sum = num1 + num2;
    return sum;
}

var result = add(10,20); //30
console.log(sum); //sum is not defined

以上代碼中的函數(shù)add()定義了一個(gè)名為sum的局部變量,該變量包含加法操作的結(jié)果。
雖然結(jié)果值從函數(shù)中返回了,但變量sum在函數(shù)外部是訪問不到的。
如果省略這個(gè)例子中的var關(guān)鍵字,那么當(dāng)add()執(zhí)行完畢后,sum也將可以訪問到。

function add(num1, num2) {
    sum = num1 + num2;
    return sum;
}

var result = add(10,20); // 30
console.log(sum); 30

在這個(gè)例子中的變量sum在被初始化賦值時(shí)沒有使用var關(guān)鍵字。
于是,當(dāng)調(diào)用完add()之后,添加到全局環(huán)境中的變量sum將繼續(xù)存在。
即使函數(shù)已經(jīng)執(zhí)行完畢,后面的代碼依舊可以訪問它。

在編寫JavaScript代碼的過程中,不聲明而直接初始化變量時(shí)一個(gè)常見的錯(cuò)誤,這樣會(huì)導(dǎo)致一些不可預(yù)估的意外。養(yǎng)成良好的習(xí)慣,在初始化變量之前,一定要先聲明,這樣就可以避免類似問題。在嚴(yán)格模式下,初始化未經(jīng)聲明的變量會(huì)導(dǎo)致錯(cuò)誤。

2.查詢標(biāo)識(shí)符

當(dāng)在某個(gè)環(huán)境中為了讀取或?qū)懭攵靡粋€(gè)標(biāo)識(shí)符時(shí),必須通過搜索來確定該標(biāo)識(shí)符實(shí)際代表什么。搜索過程從作用域鏈的前端開始,向上逐級(jí)查詢與給定名字匹配的標(biāo)識(shí)符。

如果在局部環(huán)境中找到了該標(biāo)識(shí)符,搜索過程停止,變量就緒。

如果在局部環(huán)境中沒有找到該變量,則繼續(xù)沿作用域向上搜索。

搜索過程將一直追溯到全局環(huán)境的變量對(duì)象。

如果在全局環(huán)境中也沒有找到這個(gè)標(biāo)識(shí)符,則意味著該變量尚未聲明。

var color = "blue";

function getColor() {
    return color;
}

console.log(getColor()); // "blue"

/*
window = {
    color,
    getColor = function() {
        return color;
    }
}
*/

調(diào)用本例中的函數(shù)getColor()時(shí)會(huì)引用變量color。

為了確定變量color的值,將開始一個(gè)兩步的搜索過程。

首先,在getColor()的局部環(huán)境中搜索變量對(duì)象,查找其中是否包含一個(gè)名為color的標(biāo)識(shí)符。

然后,沒有找到,對(duì)不?那就到外面的環(huán)境中找,在全局作用域中找到名為color的標(biāo)識(shí)符。

搜索到了定義這個(gè)變量的變量對(duì)象,搜索過程宣告結(jié)束。

在這個(gè)搜索過程中,如果存在一個(gè)局部的變量的定義,則搜索會(huì)自動(dòng)停止(找到了,我就不找了),不再進(jìn)入另一個(gè)變量對(duì)象。換句話說,如果局部環(huán)境中存在著同名標(biāo)識(shí)符,就不會(huì)使用位于父環(huán)境中的標(biāo)識(shí)符。

var color = "blue";

function getColor() {
    var color = "red";
    return color;
}

console.log(getColor()); //"red"

修改后的代碼在getColor()函數(shù)中聲明了一個(gè)名為color的局部變量。
調(diào)用函數(shù)時(shí),該變量就會(huì)被聲明。而當(dāng)函數(shù)中的第二行代碼執(zhí)行時(shí),意味著必須找到并返回變量color的值。
搜索過程,首先從局部環(huán)境中開始,而且在這里發(fā)現(xiàn)了一個(gè)名為color的變量,其值為“red”。
變量已經(jīng)在函數(shù)的局部環(huán)境中找到了,所以搜索停止,return語句就使用這個(gè)局部變量,并為函數(shù)返回“red”。

如果不使用window.color都無法訪問全局color變量。

變量查詢也不是沒有代價(jià)的。很明顯,訪問局部變量要比訪問全局變量更快,因?yàn)椴挥孟蛏纤阉髯饔糜蜴?。JavaScript引擎在優(yōu)化標(biāo)識(shí)符查詢方面做得不錯(cuò),因此這個(gè)差別在將來恐怕可以忽略不記。

但是,我們還是要養(yǎng)成良好的編程習(xí)慣。雖說,這個(gè)差別可以忽略不記。

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

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

相關(guān)文章

  • 前端面試閉包

    摘要:在函數(shù)內(nèi)部的變量稱之為局部變量,它可以在函數(shù)內(nèi)部讀取,在函數(shù)外部無法正常讀取,如果想要讀取函數(shù)內(nèi)部的變量則需要用到閉包。 前端面試之閉包 閉包屬于屬于JavaScript的難點(diǎn),但是在很多高級(jí)應(yīng)用都需要用到,也是前端面試中經(jīng)常會(huì)考到的點(diǎn)。 作用域 談到閉包首先必須了解作用域,ES5中,JavaScript的作用域只有兩種,一種是全局作用域,變量在整個(gè)程序中一直存在,所有地方都可以讀?。?..

    jackzou 評(píng)論0 收藏0
  • ES6 變量作用與提升:變量生命周期詳解

    摘要:不同的是函數(shù)體并不會(huì)再被提升至函數(shù)作用域頭部,而僅會(huì)被提升到塊級(jí)作用域頭部避免全局變量在計(jì)算機(jī)編程中,全局變量指的是在所有作用域中都能訪問的變量。 ES6 變量作用域與提升:變量的生命周期詳解從屬于筆者的現(xiàn)代 JavaScript 開發(fā):語法基礎(chǔ)與實(shí)踐技巧系列文章。本文詳細(xì)討論了 JavaScript 中作用域、執(zhí)行上下文、不同作用域下變量提升與函數(shù)提升的表現(xiàn)、頂層對(duì)象以及如何避免創(chuàng)建...

    lmxdawn 評(píng)論0 收藏0
  • 筆記:javascript 深入理解

    摘要:所有作為參數(shù)傳入的值都會(huì)成為對(duì)象的數(shù)組元素執(zhí)行上下文的生命周期創(chuàng)建階段在這個(gè)階段中,執(zhí)行上下文會(huì)分別創(chuàng)建變量對(duì)象,建立作用域鏈,以及確定的指向。 JavaScript深入之從原型到原型鏈 構(gòu)造函數(shù)->原型每個(gè)函數(shù)都有一個(gè) prototype 屬性,指向?qū)嵗脑驮停好恳粋€(gè)JavaScript對(duì)象(null除外)在創(chuàng)建的時(shí)候就會(huì)與之關(guān)聯(lián)另一個(gè)對(duì)象,這個(gè)對(duì)象就是我們所說的原型實(shí)例->原型...

    everfight 評(píng)論0 收藏0
  • JS模仿塊級(jí)作用_立即執(zhí)行函數(shù)

    摘要:模仿塊級(jí)作用域立即執(zhí)行函數(shù)前言最近在細(xì)讀高級(jí)程序設(shè)計(jì),對(duì)于我而言,中文版,書中很多地方一筆帶過,所以用自己所理解的,嘗試細(xì)致解讀下。語法如下這里是塊級(jí)作用域以上代碼定義并立即調(diào)用了一個(gè)匿名函數(shù)。 模仿塊級(jí)作用域-立即執(zhí)行函數(shù) 前言:最近在細(xì)讀Javascript高級(jí)程序設(shè)計(jì),對(duì)于我而言,中文版,書中很多地方一筆帶過,所以用自己所理解的,嘗試細(xì)致解讀下。如有紕漏或錯(cuò)誤,會(huì)非常感謝您的指...

    NoraXie 評(píng)論0 收藏0
  • 夯實(shí)基礎(chǔ)-作用與閉包

    摘要:作用域分類作用域共有兩種主要的工作模型。換句話說,作用域鏈?zhǔn)腔谡{(diào)用棧的,而不是代碼中的作用域嵌套。詞法作用域詞法作用域中,又可分為全局作用域,函數(shù)作用域和塊級(jí)作用域。 一篇鞏固基礎(chǔ)的文章,也可能是一系列的文章,梳理知識(shí)的遺漏點(diǎn),同時(shí)也探究很多理所當(dāng)然的事情背后的原理。 為什么探究基礎(chǔ)?因?yàn)槟悴蝗ッ嬖嚹憔筒恢阑A(chǔ)有多重要,或者是說當(dāng)你的工作經(jīng)歷沒有亮點(diǎn)的時(shí)候,基礎(chǔ)就是檢驗(yàn)?zāi)愫脡牡囊豁?xiàng)...

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

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

0條評(píng)論

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