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

資訊專欄INFORMATION COLUMN

代碼真的被提升了嗎?

weknow619 / 3175人閱讀

摘要:為啥因為變量提升,變量的聲明被提升到當前作用域的頂部了。也就是可以想象成這樣此外,還有函數提升,和變量提升類似和被提升了,所以不會報錯。開始處理函數聲明,再次提醒,函數表達式不會被處理。

變量提升 & 函數提升
function f() {
    console.log(a); // ?
    var a = 1;
}
f();

簡單簡單,打印結果是 undefined。為啥?因為變量提升,變量 a 的聲明被提升到當前作用域的頂部了。也就是可以想象成這樣:

function f() {
    var a;
    console.log(a);
    a = 1;
}

此外,還有函數提升,和變量提升類似:

f1();

f2();

function f1() { console.log(1) }

function f2() { console.log(2) }

f1 和 f2 被提升了,所以不會報錯。很多文章中都會經常提到提升這個概念。
但是,這是真的嗎?JS 解釋器在執行代碼時還順帶幫你變動一下代碼的順序?想想也覺得不太可能嘛~那么到底是咋回事捏?

可執行代碼

JavaScript 的可執行代碼(executable code)有三種,分別為 全局代碼函數代碼以及 eval 代碼。鑒于 eval 不被推薦使用,咱就不理它。

執行上下文

當執行全局代碼時,會創建一個全局執行上下文。當執行一個函數的時候,會創建一個函數執行上下文。全局執行上下文只會有一個,而函數執行上下文可以有很多很多個。JS 引擎會創建 執行上下文棧(execution context stack, ECS)去管理這些執行上下文。我們以函數執行上下文為例。

變量對象

對于一個執行上下文而言,可以抽象化為這樣一個對象:

contextObject = {
    VariableObject,
    ScopeChain,
    thisValue
}

其中變量對象(Variable Object,VO)是包含與當前執行上下文相關的數據作用域,它存儲著當前上下文中定義的變量聲明、函數聲明(注意:不包含函數表達式),另外函數執行上下文中還會有參數。

變量對象是一個抽象概念,在不同的執行上下文中會以不同的對象呈現。比如在全局上下文中,變量對象就是全局對象本身(這也是為什么我們能夠通過全局對象的屬性名稱引用全局變量)。而對于函數執行上下文,是用活動對象(Activation Object,AO)來表示變量對象的,我們訪問的便是活動對象上的屬性。

執行過程

執行上下文中的代碼會被分出兩個階段進行處理,分別為:

進入執行上下文,即分析創建階段

執行代碼,即執行階段

分析創建階段

此時進入執行上下文,但在開始執行代碼之前。此時的變量對象:

如果是函數上下文,那么會通過函數的 arguments 屬性初始化,并處理形參。此時變量對象中會包含一個 arguments 對象,以及所有的形參,并且會檢查是否有與之對應的實參,有則值初始化為實參的值,沒有的話就設為 undefined。

處理函數聲明。開始處理函數聲明,再次提醒,函數表達式不會被處理。此時會檢查變量對象中是否已經有同名屬性,如果有,則替換它,如果沒有則創建屬性,值初始化為對應的函數對象。

處理變量聲明。與處理函數聲明不同的是,如果變量對象中存在有同名屬性,此時會跳過該變量不做任何事,即不會產生覆蓋,如果沒有則創建屬性并初始化為 undefined。

了解了第一個階段,那么來看個例子:

function f(a, b) {
    var c = 3;
    function d() {};
    var e = function() {};
    (function f() {});
}

f(1, 2);

當執行 f 函數時,進入執行上下文,我們可以描述出此時的 AO:

AO = {
    arguments: {
        0: 1,
        1: 2,
        length: 2
    },
    a: 1,
    b: 2,
    c: undefined,
    d: reference to function() {},
    e: undefined,
}
// 注意:(function f() {}) 為函數表達式,不會被處理
執行階段

執行階段就相對簡單,代碼順序執行,并且會根據代碼去修改變量對象中的值,所以當函數執行完后的 AO 會是:

AO = {
    arguments: {
        0: 1,
        1: 2,
        length: 2
    },
    a: 1,
    b: 2,
    c: 3,
    d: reference to function() {},
    e: reference to function() {},
}
總結

綜上所述:

全局上下文的變量對象即是全局對象;

函數上下文的變量對象會以 arguments 對象初始化;

在第一個階段會依次給變量對象添加形參(函數上下文)、函數聲明、變量聲明;

在第二個階段,會修改變量對象中的屬性值。

思考題
console.log(f); // ?

function f() {}
var f = 1;

打印結果會是一個函數對象。因為第一個階段中先處理函數聲明后處理變量聲明,當處理變量聲明時變量對象中已經存在同名屬性 f,不會做任何事直接跳過,所以 f 的值會是一個函數。

你也可以多找幾道題嘗試分析以加深理解。當然,日常工作中還是直接想成提升來得方便些,只是希望通過本文能讓你了解到一些背后的事情。最后,如果文中有任何錯誤或不足之處,還請指出~

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/104225.html

相關文章

  • 8道經典JavaScript面試題解析,你真的掌握JavaScript了嗎

    摘要:瀏覽器的主要組成包括有調用堆棧,事件循環,任務隊列和。好了,現在有了前面這些知識,我們可以看一下這道題的講解過程實現步驟調用會將函數放入調用堆棧。由于調用堆棧是空的,事件循環將選擇回調并將其推入調用堆棧進行處理。進程再次重復,堆棧不會溢出。 JavaScript是前端開發中非常重要的一門語言,瀏覽器是他主要運行的地方。JavaScript是一個非常有意思的語言,但是他有很多一些概念,大...

    taowen 評論0 收藏0
  • 春陽:SaaS已死,下一個

    摘要:中國的是一個陰謀讓我們首先回到的初衷。春陽曾經分享過的藏寶圖報告里有過一個關于家廠商毛利水平的統計,如下圖所示,其中位數是。每一年,都會有人問我,春陽,你覺得SaaS行業到時候了嗎?每一年,都會有媒體發文,SaaS已來,未來可期....是的,每一年...行業的媒體人喜歡給SaaS灌雞湯是沒有毛病的,本身這就是個留不住人才、熬不出日子的行業,如果我們再看衰它,媒體本身也是活不下去了…對這個問題...

    rainyang 評論0 收藏0
  • PHP socket初探 --- 硬著頭皮繼續libevent(二)

    摘要:類就是產生各種不同類型事件的產出器,比如定時器事件讀寫事件等等,為了提升民族榮譽感,我們將這些各種事件比作各種戰斗機比如殲殲和殲。類就相對容易介入了,這玩意顯然就是一個航空母艦了,為了提升民族榮譽感,我們就把類當作是遼寧艦。 [原文地址:https://blog.ti-node.com/blog...] 實際上php.net上是有event擴展的使用說明手冊,但是呢,對于初學者來說卻并...

    jokester 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<