JS 預(yù)編譯

JS 運行三部曲

語法分析

語法分析很簡單,就是引擎檢查你的代碼有沒有什么低級的語法錯誤

預(yù)編譯

預(yù)編譯發(fā)生在代碼執(zhí)行的前一刻,預(yù)編譯簡單理解就是在內(nèi)存中開辟一些空間,存放一些變量與函數(shù) ;

解析執(zhí)行

解釋執(zhí)行顧名思義便是執(zhí)行代碼了

預(yù)編譯前奏

暗示全局變量 imply global

任何變量,如果變量未經(jīng)申明就賦值,此變量就為 全局對象 所有。

    a = 1;
    console.log(window.a);
    function test() {
        var a = b = 2;
    }
    test();
    console.log(window.b);

全局變量

一切申明的 全局變量, 全是 window 的屬性, window 就是全局的域

GO 和 AO

JS 在執(zhí)行前會產(chǎn)生一個 GO ,也就是我們說的全局作用域 。 當(dāng)一個方法被調(diào)用時會形成一個局部作用域 AO

全局代碼在執(zhí)行的時候,先是 變量提升 , 在全局作用域內(nèi)添加 屬性,然后是 函數(shù)(以函數(shù)聲明創(chuàng)建的函數(shù))提升,再是代碼執(zhí)行

我們先來個簡單的小栗子來看看

    var b = 2;
    console.log(b); 
    console.log(b);
    var b = 2;

此時我們打印出來 b 的值為 undefined,那我們不定義 b 直接 打印 b 是什么情況呢

console.log(b);

結(jié)果如上圖 瀏覽器報錯.

為什么在 console.log 前,后和不定義 b 會有如此大的差別,這就是預(yù)編譯起到的作用

我們再看看下面這個列子

    console.log(a);
    var a = 123;
    function a() {
    }
    console.log(a);
微信圖片_20200111143158.png

結(jié)果怎么來的呢???

那我們就得看下面的 預(yù)編譯 四部曲

預(yù)編譯四部曲

  • 創(chuàng)建 GO/AO 對象

  • 找形參和變量申明,將變量和形參名作為 AO 屬性名,值為 undefined

  • 將實參值和形參值統(tǒng)一

  • 在函數(shù)體里面找函數(shù)申明,值賦予 函數(shù)體

這四部是什么意思呢,我們舉個例子看看:

    function fn(a) {
        console.log(a);
        var a = 123;
        console.log(a);
        function a() { }

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

大家覺得應(yīng)該輸出什么呢?

我們來分析下:

首先方法調(diào)用形成一個局部 *AO


AO{

}

找方法里面的形參和變量申明, fn 里面 只有 a 和 b,作為 AO 的屬性并把值設(shè)置為 undefined


AO{
    a:undefined,
    b:undefined
}

然后將形參和實參的值統(tǒng)一,什么意思呢,就是給 形參 a 賦值為 實參 1,此時的 AO:


AO{
    a:1,
    b:undefined
}

最后一步函數(shù)體找函數(shù)申明,并賦值為函數(shù)體, 我們找到了 函數(shù)申明 function a() { } ,有人會問 b呢,不好意思 b 是 函數(shù)表達式,因此忽略,此時 AO 為:


AO{
    a:function a() { },
    b:undefined
}

到此 函數(shù)預(yù)編譯完成,下面開始執(zhí)行:

  • 第一次 console.log(a) 打印即為 AO 里面的 a => function a() { }

  • 第二次 console.log(a) 執(zhí)行 a 的賦值,此時 a =>123

  • 第三次 console.log(a) 函數(shù)function a() { } 已經(jīng)預(yù)編譯申明過, 因此直接忽略, a 還是為 123

  • 第一次 console.log(b) 打印即為 AO 里面的 b => undefined

  • 第二次 console.log(b) 執(zhí)行 b 的賦值,此時 b =>function () { }

我們來看看打印的是否如我們分析的這樣:


fn.png

看來沒有問題。

好了,我們已經(jīng)知道了 預(yù)編譯的過程,那讓我們再來一題看看:


function test() {
    console.log(b);
    if (a) {
        var b = 100;
    }
    
    c = 234;
    console.log(b);

    console.log(c);
}

var a;
test();
a = 10;
console.log(a);
console.log(c);

一樣的,我們首先生成 GO,AO

GO{
    a:undefined
}

AO{
    b:undefined
}
  • 第一次打印 b 的值 為 undefined 沒問題,

  • 此時 AO 中沒有a 屬性,往上找全局屬性 GO ,ok a 為 undefined,條件不成立 b 還是 undefined

  • 打印 c 沒什么好說的,直接就是 234

  • 函數(shù) test() 執(zhí)行完畢 下面 a 進行復(fù)制, 因此 打印 a 為 10

  • 打印 c 相當(dāng)于 訪問 window.c 因此還是 234

小練習(xí)


    a = 100;
    function deme(e) {
        function a() { }
        arguments[0] = 2;
        console.log(e);
        if (a) {
            var b = 123;
            var c = function () { }
        }
        var c;
        a = 10;
        var a;
        console.log(b);
        f = 123;
        console.log(c);
        console.log(a);
    }

    var a;
    deme(1);
    console.log(a);
    console.log(f);

總結(jié)

  1. 未經(jīng)申明就賦值,此變量就是全局變量所有,一切申明的全局變量,全是 window 屬性

  2. 預(yù)編譯發(fā)生在 變量申明函數(shù)申明, 匿名函數(shù)函數(shù)表達式 不參與預(yù)編譯

  3. 變量 聲明提升—無論變量調(diào)用和聲明的位置是前是后,系統(tǒng)總會把聲明移到調(diào)用前,注意僅僅只是聲明,所以值是 undefined

  4. 函數(shù)聲明整體提升-無論函數(shù)調(diào)用和聲明的位置是前是后,系統(tǒng)總會把函數(shù)聲明移到調(diào)用前面.如果函數(shù)名同形參或變量名同名,則會賦值為 函數(shù)體

  5. 只有在解析執(zhí)行才會對變量初始化

覺得不錯請幫忙點個贊,謝謝!!!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 預(yù)編譯是js的一個特色,也算是閉包之前最難的一個知識點。 預(yù)編譯有4句公式,而這4句公式只要背熟就能理解預(yù)編譯。 ...
    德育處主任閱讀 1,532評論 0 7
  • 之前學(xué)習(xí)了一些預(yù)編譯的知識,一直沒有作總結(jié),今天總結(jié)一下。 大家都知道,javascript是解釋性語言,主要特點...
    蛋撻一點也不甜閱讀 454評論 1 0
  • 輸出: 原因: js執(zhí)行前會進行預(yù)編譯全局預(yù)編譯GO(Global Object)創(chuàng)建GO對象給全局變量賦值 un...
    文刀強閱讀 1,948評論 0 2
  • JS三部曲:語法分析:js代碼的執(zhí)行是讀一行代碼執(zhí)行一行,但在執(zhí)行之前系統(tǒng)會先對js進行全面掃描檢查是否存在低級的...
    WangYatao閱讀 1,954評論 0 4
  • 6歲時我最想要個芭比娃娃,可以每天給她穿衣服,12歲時我想數(shù)學(xué)可以考100分,父母可以請我吃好吃的,18歲時我...
    思域22閱讀 395評論 1 0

友情鏈接更多精彩內(nèi)容