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

資訊專欄INFORMATION COLUMN

JavaScript的執(zhí)行上下文與執(zhí)行環(huán)境

ZHAO_ / 2679人閱讀

摘要:也就是說,當(dāng)代碼執(zhí)行的時(shí)候,會(huì)進(jìn)入不同的執(zhí)行上下文,這些執(zhí)行上下文就構(gòu)成了一個(gè)執(zhí)行上下文棧,。它是一個(gè)與上下文相關(guān)的特殊對(duì)象,其中存儲(chǔ)了在上下文中定義的變量和函數(shù)聲明。

明白的人,看標(biāo)題這么寫,會(huì)發(fā)現(xiàn)是有問題的,對(duì)的,在JavaScript中執(zhí)行上下文執(zhí)行環(huán)境是同一個(gè)東西,標(biāo)題這么寫肯定是有問題的。但是有些人是搞不清執(zhí)行上下文執(zhí)行環(huán)境的,所以我才這么寫,以便于他們好搜索到。下面我們統(tǒng)稱執(zhí)行上下文Execution context,EC)。

在JavaScript的運(yùn)行過程中,經(jīng)常會(huì)遇到一些"奇怪"的行為,不理解為什么JavaScript會(huì)這么工作。這時(shí)候可能就需要了解一下JavaScript執(zhí)行過程中的相關(guān)內(nèi)容了。

執(zhí)行上下文

在JavaScript中有三種代碼運(yùn)行環(huán)境:

Global Code
    JavaScript代碼開始運(yùn)行的默認(rèn)環(huán)境
Function Code
    代碼進(jìn)入一個(gè)JavaScript函數(shù)
Eval Code
    使用eval()執(zhí)行代碼

為了表示不同的運(yùn)行環(huán)境,JavaScript中有一個(gè)執(zhí)行上下文(Execution context,EC)的概念。也就是說,當(dāng)JavaScript代碼執(zhí)行的時(shí)候,會(huì)進(jìn)入不同的執(zhí)行上下文,這些執(zhí)行上下文就構(gòu)成了一個(gè)執(zhí)行上下文棧(Execution context stack,ECS)。

例如對(duì)如下面的JavaScript代碼:

var a = "global var";

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

function outerFunc(){
    var b = "var in outerFunc";
    console.log(b);
    
    function innerFunc(){
        var c = "var in innerFunc";
        console.log(c);
        foo();
    }
    
    innerFunc();
}


outerFunc()

代碼首先進(jìn)入Global Execution Context,然后依次進(jìn)入outerFunc,innerFunc和foo的執(zhí)行上下文,執(zhí)行上下文棧就可以表示為:


當(dāng)JavaScript代碼執(zhí)行的時(shí)候,第一個(gè)進(jìn)入的總是默認(rèn)的Global Execution Context,所以說它總是在ECS的最底部。

對(duì)于每個(gè)Execution Context都有三個(gè)重要的屬性,變量對(duì)象(Variable object,VO),作用域鏈(Scope chain)和this。這三個(gè)屬性跟代碼運(yùn)行的行為有很重要的關(guān)系,下面會(huì)一一介紹。

當(dāng)然,除了這三個(gè)屬性之外,根據(jù)實(shí)現(xiàn)的需要,Execution Context還可以有一些附加屬性。

VO和AO

從上面看到,在Execution Context中,會(huì)保存變量對(duì)象(Variable object,VO),下面就看看變量對(duì)象是什么。

變量對(duì)象(Variable object)

變量對(duì)象是與執(zhí)行上下文相關(guān)的數(shù)據(jù)作用域。它是一個(gè)與上下文相關(guān)的特殊對(duì)象,其中存儲(chǔ)了在上下文中定義的變量和函數(shù)聲明。也就是說,一般VO中會(huì)包含以下信息:

變量 (var, Variable Declaration);
函數(shù)聲明 (Function Declaration, FD);
函數(shù)的形參

當(dāng)JavaScript代碼運(yùn)行中,如果試圖尋找一個(gè)變量的時(shí)候,就會(huì)首先查找VO。對(duì)于前面例子中的代碼,Global Execution Context中的VO就可以表示如下:

注意,假如上面的例子代碼中有下面兩個(gè)語句,Global VO仍將不變。

(function bar(){}) // function expression, FE
baz = "property of global object"

也就是說,對(duì)于VO,是有下面兩種特殊情況的:

1.函數(shù)表達(dá)式(與函數(shù)聲明相對(duì))不包含在VO之中
2.沒有使用var聲明的變量(這種變量是,"全局"的聲明方式,只是給Global添加了一個(gè)屬性,并不在VO中)
活動(dòng)對(duì)象(Activation object)

只有全局上下文的變量對(duì)象允許通過VO的屬性名稱間接訪問;在函數(shù)執(zhí)行上下文中,VO是不能直接訪問的,此時(shí)由激活對(duì)象(Activation Object,縮寫為AO)扮演VO的角色。激活對(duì)象 是在進(jìn)入函數(shù)上下文時(shí)刻被創(chuàng)建的,它通過函數(shù)的arguments屬性初始化。

Arguments Objects 是函數(shù)上下文里的激活對(duì)象AO中的內(nèi)部對(duì)象,它包括下列屬性:

callee:指向當(dāng)前函數(shù)的引用
length: 真正傳遞的參數(shù)的個(gè)數(shù)
properties-indexes:就是函數(shù)的參數(shù)值(按參數(shù)列表從左到右排列)

對(duì)于VO和AO的關(guān)系可以理解為,VO在不同的Execution Context中會(huì)有不同的表現(xiàn):當(dāng)在Global Execution Context中,可以直接使用VO;但是,在函數(shù)Execution Context中,AO就會(huì)被創(chuàng)建。

當(dāng)上面的例子開始執(zhí)行outerFunc的時(shí)候,就會(huì)有一個(gè)outerFunc的AO被創(chuàng)建:

通過上面的介紹,我們現(xiàn)在了解了VO和AO是什么,以及他們之間的關(guān)系了。下面就需要看看JavaScript解釋器是怎么執(zhí)行一段代碼,以及設(shè)置VO和AO了。

細(xì)看Execution Context

當(dāng)一段JavaScript代碼執(zhí)行的時(shí)候,JavaScript解釋器會(huì)創(chuàng)建Execution Context,其實(shí)這里會(huì)有兩個(gè)階段:

1.創(chuàng)建階段(當(dāng)函數(shù)被調(diào)用,但是開始執(zhí)行函數(shù)內(nèi)部代碼之前)
    創(chuàng)建Scope chain
    創(chuàng)建VO/AO(variables, functions and arguments)
    設(shè)置this的值
2.激活/代碼執(zhí)行階段
    設(shè)置變量的值、函數(shù)的引用,然后解釋/執(zhí)行代碼

這里想要詳細(xì)介紹一下"創(chuàng)建VO/AO"中的一些細(xì)節(jié),因?yàn)檫@些內(nèi)容將直接影響代碼運(yùn)行的行為。

對(duì)于"創(chuàng)建VO/AO"這一步,JavaScript解釋器主要做了下面的事情:

1.根據(jù)函數(shù)的參數(shù),創(chuàng)建并初始化arguments object
2.掃描函數(shù)內(nèi)部代碼,查找函數(shù)聲明(Function declaration)
    對(duì)于所有找到的函數(shù)聲明,將函數(shù)名和函數(shù)引用存入VO/AO中
    如果VO/AO中已經(jīng)有同名的函數(shù),那么就進(jìn)行覆蓋
3.掃描函數(shù)內(nèi)部代碼,查找變量聲明(Variable declaration)
    對(duì)于所有找到的變量聲明,將變量名存入VO/AO中,并初始化為"undefined"
    如果變量名稱跟已經(jīng)聲明的形式參數(shù)或函數(shù)相同,則變量聲明不會(huì)干擾已經(jīng)存在的這類屬性

看下面的例子:

function foo(i) {
    var a = "hello";
    var b = function privateB() {

    };
    function c() {

    }
}

foo(22);

對(duì)于上面的代碼,在"創(chuàng)建階段",可以得到下面的Execution Context object:

fooExecutionContext = {
    scopeChain: { ... },
    variableObject: {
        arguments: {
            0: 22,
            length: 1
        },
        i: 22,
        c: pointer to function c()
        a: undefined,
        b: undefined
    },
    this: { ... }
}

在"激活/代碼執(zhí)行階段",Execution Context object就被更新為:

fooExecutionContext = {
    scopeChain: { ... },
    variableObject: {
        arguments: {
            0: 22,
            length: 1
        },
        i: 22,
        c: pointer to function c()
        a: "hello",
        b: pointer to function privateB()
    },
    this: { ... }
}

例子分析

前面介紹了Execution Context,VO/AO等這么多的理論知識(shí),當(dāng)然是為了方便我們?nèi)シ治龃a中的一些行為。這里,就通過幾個(gè)簡(jiǎn)單的例子,結(jié)合上面的概念來分析結(jié)果。

Example 1
首先看第一個(gè)例子:

(function(){
    console.log(bar);
    console.log(baz);
    
    var bar = 20;
    
    function baz(){
        console.log("baz");
    }
    
})()

在Chrome中運(yùn)行代碼運(yùn)行后將輸出:

代碼解釋:匿名函數(shù)會(huì)首先進(jìn)入"創(chuàng)建結(jié)果",JavaScript解釋器會(huì)創(chuàng)建一個(gè)"Function Execution Context",然后創(chuàng)建Scope chain,VO/AO和this。根據(jù)前面的介紹,解釋器會(huì)掃描函數(shù)和變量聲明,如下的AO會(huì)被創(chuàng)建:

所以,對(duì)于bar,我們會(huì)得到"undefined"這個(gè)輸出,表現(xiàn)的行為就是,我們?cè)诼暶饕粋€(gè)變量之前就訪問了這個(gè)變量。這個(gè)就是JavaScript中"Hoisting"。

Example 2
接著上面的例子,進(jìn)行一些修改:

(function(){
    console.log(bar);
    console.log(baz);
    
    bar = 20;
    console.log(window.bar);
    console.log(bar);
    
    function baz(){
        console.log("baz");
    }
    
})()

運(yùn)行這段代碼會(huì)得到"bar is not defined(…)"錯(cuò)誤。當(dāng)代碼執(zhí)行到"console.log(bar);"的時(shí)候,會(huì)去AO中查找"bar"。但是,根據(jù)前面的解釋,函數(shù)中的"bar"并沒有通過var關(guān)鍵字聲明,所有不會(huì)被存放在AO中,也就有了這個(gè)錯(cuò)誤。

注釋掉"console.log(bar);",再次運(yùn)行代碼,可以得到下面結(jié)果。"bar"在"激活/代碼執(zhí)行階段"被創(chuàng)建。

Example 3
現(xiàn)在來看最后一個(gè)例子:

(function(){
    console.log(foo);
    console.log(bar);
    console.log(baz);
    
    var foo = function(){};
    
    function bar(){
        console.log("bar");
    }
    
    var bar = 20;
    console.log(bar);
    
    function baz(){
        console.log("baz");
    }
    
})()

代碼的運(yùn)行結(jié)果為:

代碼中,最"奇怪"的地方應(yīng)該就是"bar"的輸出了,第一次是一個(gè)函數(shù),第二次是"20"。

其實(shí)也很好解釋,回到前面對(duì)"創(chuàng)建VO/AO"的介紹,在創(chuàng)建VO/AO過程中,解釋器會(huì)先掃描函數(shù)聲明,然后"foo: "就被保存在了AO中;但解釋器掃描變量聲明的時(shí)候,雖然發(fā)現(xiàn)"var bar = 20;",但是因?yàn)?foo"在AO中已經(jīng)存在,所以就沒有任何操作了。

但是,當(dāng)代碼執(zhí)行到第二句"console.log(bar);"的時(shí)候,"激活/代碼執(zhí)行階段"已經(jīng)把AO中的"bar"重新設(shè)置了。

作者:田小計(jì)劃
出處:http://www.cnblogs.com/wilber...
本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。

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

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

相關(guān)文章

  • javascript高級(jí)程序設(shè)計(jì)》筆記:內(nèi)存執(zhí)行環(huán)境

    摘要:因此,所有在方法中定義的變量都是放在棧內(nèi)存中的當(dāng)我們?cè)诔绦蛑袆?chuàng)建一個(gè)對(duì)象時(shí),這個(gè)對(duì)象將被保存到運(yùn)行時(shí)數(shù)據(jù)區(qū)中,以便反復(fù)利用因?yàn)閷?duì)象的創(chuàng)建成本通常較大,這個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū)就是堆內(nèi)存。 上一篇:《javascript高級(jí)程序設(shè)計(jì)》筆記:繼承近幾篇博客都會(huì)圍繞著圖中的知識(shí)點(diǎn)展開 showImg(https://segmentfault.com/img/bVY0C4?w=1330&h=618);...

    fuyi501 評(píng)論0 收藏0
  • 由 ECMA 規(guī)范解讀 Javascript執(zhí)行下文概念

    摘要:不包括作為其嵌套函數(shù)的被解析的源代碼。作用域鏈當(dāng)代碼在一個(gè)環(huán)境中執(zhí)行時(shí),會(huì)創(chuàng)建變量對(duì)象的一個(gè)作用域鏈。棧結(jié)構(gòu)最頂層的執(zhí)行環(huán)境稱為當(dāng)前運(yùn)行的執(zhí)行環(huán)境,最底層是全局執(zhí)行環(huán)境。無限制函數(shù)上下文。或者拋出異常退出一個(gè)執(zhí)行環(huán)境。 前言 其實(shí)規(guī)范這東西不是給人看的,它更多的是給語言實(shí)現(xiàn)者提供參考。但是當(dāng)碰到問題找不到答案時(shí),規(guī)范往往能提供想要的答案 。偶爾讀一下能夠帶來很大的啟發(fā)和思考,如果只讀一...

    daryl 評(píng)論0 收藏0
  • 深入理解JavaScript (1) —— 執(zhí)行下文執(zhí)行下文

    摘要:執(zhí)行上下文棧通過上文我們知道預(yù)處理全局代碼時(shí),會(huì)產(chǎn)生一個(gè)執(zhí)行上下文環(huán)境。實(shí)現(xiàn)這一壓棧出棧過程的機(jī)制就是執(zhí)行上下文棧。 JavaScript的解析(預(yù)處理)與執(zhí)行 詳見:http://www.cnblogs.com/foodoi... 執(zhí)行上下文 JavaScript在執(zhí)行一個(gè)代碼段之前,即解析(預(yù)處理)階段,會(huì)先進(jìn)行一些準(zhǔn)備工作,例如掃描JS中var定義的變量、函數(shù)名等,進(jìn)而生成執(zhí)行上...

    lidashuang 評(píng)論0 收藏0
  • 前端進(jìn)擊巨人(一):執(zhí)行下文執(zhí)行棧,變量對(duì)象

    摘要:在中,通過棧的存取方式來管理執(zhí)行上下文,我們可稱其為執(zhí)行棧,或函數(shù)調(diào)用棧。而處于棧頂?shù)氖钱?dāng)前正在執(zhí)行函數(shù)的執(zhí)行上下文,當(dāng)函數(shù)調(diào)用完成后,它就會(huì)從棧頂被推出理想的情況下,閉包會(huì)阻止該操作,閉包后續(xù)文章深入詳解。 寫在開篇 已經(jīng)不敢自稱前端小白,曾經(jīng)吹過的牛逼總要一點(diǎn)點(diǎn)去實(shí)現(xiàn)。 正如前領(lǐng)導(dǎo)說的,自己喝酒吹過的牛皮,跪著都得含著淚去實(shí)現(xiàn)。 那么沒有年終完美總結(jié),來個(gè)新年莽撞開始可好。 進(jìn)擊巨...

    _Suqin 評(píng)論0 收藏0
  • JavaScript執(zhí)行下文和變量對(duì)象

    摘要:以上簡(jiǎn)單總結(jié)了下對(duì)執(zhí)行上下文和變量對(duì)象的理解,主要在于記錄總結(jié)一下學(xué)習(xí)成果,目前文章的水平實(shí)在不敢談分享。 執(zhí)行上下文(Execution Context) 文章同步到github javaScript中的執(zhí)行上下文和變量對(duì)象 JavaScript代碼執(zhí)行的過程,包括編譯和執(zhí)行兩個(gè)階段,編譯就是通過詞法分析,構(gòu)建抽象抽象語法樹,并編譯成機(jī)器識(shí)別的指令,在JavaScript代碼編譯階段...

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

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

0條評(píng)論

ZHAO_

|高級(jí)講師

TA的文章

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