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);

結(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 () { }
我們來看看打印的是否如我們分析的這樣:

看來沒有問題。
好了,我們已經(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é)
未經(jīng)申明就賦值,此變量就是全局變量所有,一切申明的全局變量,全是 window 屬性
預(yù)編譯發(fā)生在 變量申明 和 函數(shù)申明, 匿名函數(shù) 和 函數(shù)表達式 不參與預(yù)編譯
變量 聲明提升—無論變量調(diào)用和聲明的位置是前是后,系統(tǒng)總會把聲明移到調(diào)用前,注意僅僅只是聲明,所以值是 undefined
函數(shù)聲明整體提升-無論函數(shù)調(diào)用和聲明的位置是前是后,系統(tǒng)總會把函數(shù)聲明移到調(diào)用前面.如果函數(shù)名同形參或變量名同名,則會賦值為 函數(shù)體
只有在解析執(zhí)行才會對變量初始化
覺得不錯請幫忙點個贊,謝謝!!!