JavaScript 預編譯與作用域
JavaScript 預編譯的程序和作用域的分析步驟是 JS 學習中重要的一環,能夠幫助我們知道代碼的執行順序,更好理解閉包的概念
預編譯
-
JavaScript 執行步驟
檢查通篇的語法錯誤 -> 預編譯 -> 解釋執行
-
暗示全域變數
變數不宣告直接賦值,掛載到 window 物件下
a = 1; console.log(a); // 1 function test() { var b = c = 1; } test(); console.log(c); // 列印 1,c 未宣告,直接賦值,暗示全域變數 console.log(window.b); // undefined,列印物件不存在屬性,回傳 undefined console.log(b); // 報錯 -
預編譯程序
函式宣告整體提升
變數宣告提升,賦值不提升
test(); // 放在前面可以執行 function test() { } console.log(a); // 列印出 undefined var a = 1; // 宣告提升,賦值不提升
GO
-
global object,全域背景關系,即 window 物件
-
在全域執行的前一刻,生成 GO,即變數宣告提升和函式宣告提升
-
步驟:尋找變數宣告 -> 尋找函式宣告 -> 順序執行(同名覆寫)
var a = 1; // (1) function a() { console.log(2); } console.log(a); // (2) // 全域預編譯 // 變數宣告 a -> GO{a: undefined} // 函式宣告 a(){} -> GO{a: a(){}} // 全域執行 // 執行 (1) -> GO{a: 1} // 執行 (2),列印 1console.log(a); // (1) var a = 1; // (2) console.log(a); // (3) function a() { console.log(2); } // 全域預編譯 // 變數宣告 a -> GO{a: undefined} // 函式宣告 a(){} -> GO{a: a(){}} // 全域執行 // 執行 (1),列印 a(){...} // 執行 (2) -> GO{a: 1} // 執行 (3),列印 1
AO
-
activation object,函式背景關系,即活躍物件
-
每個函式都有自己的 AO,函式執行前一刻生成,執行完以后銷毀
-
步驟:尋找變數宣告 -> 尋找形參 -> 形參實參映射 ->尋找函式宣告 -> 順序執行(同名覆寫)
-
注意:AO 中有 var a 宣告,不會找 GO 里的 a
function test(a) { console.log(a); // (1) var a = 1; // (2) console.log(a); // (3) function a() {} console.log(a); // (4) var b = function() {} // (5) console.log(b); // (6) function d() {} } test(2); // 全域預編譯 // 函式宣告 test(){} -> GO{a: test(){}} // 全域執行 // 執行到 test(2),函式 test 預編譯 // 變數宣告 a, b -> test_AO{a: undefined, b: undefined} // 引數映射 -> test_AO{a: 2, b: undefined} // 函式宣告 -> test_AO{a: a(){}, b:undefined, d: d(){}} // 函式 test 執行 // 執行 (1),列印 a(){} // 執行 (2) -> test_AO{a: 1, b: undefined, d: d(){}} // 執行 (3),列印 1 // 執行 (4),列印 1 // 執行 (5) -> test_AO{a: 1, b: (){}, d: d(){}} // 執行 (6),列印 (){} // 函式 test 執行完畢,test_AO 銷毀 -
練習
a = 1; // (1) function test() { console.log(a); // (2) a = 2; // (3) console.log(a); // (4) if(a) { // (5),預編譯時不看 if,因為沒有執行該句 var a = 3; } console.log(a); // (6) } test(); var a; // 全域預編譯 // 變數宣告、函式宣告 -> GO{a: undefined, test: test(){}} // 全域執行 // 執行 (1) -> GO{a: 1, test: test(){}} // 執行到 test(),函式 test 預編譯 // 變數宣告 -> test_AO{a: undefined} // 函式 test 執行 // 執行 (2),列印 undefined // 執行 (3) -> AO{a: 2} // 執行 (4),列印 2 // 執行 (5) -> AO{a: 3} // 執行 (6) -> 列印 3 // 函式 test 執行完畢,test_AO 銷毀
作用域
-
函式的屬性
函式是一種參考型別
有一些原生屬性可以利用,也有一些屬性不能訪問,是 js 引擎內部固有的隱式屬性
[[scope]] 就是 JS 內部隱式屬性,是函式存盤作用域鏈的容器
function test() { } console.log(test.name); // test console.log(test.length); // 0 -
作用域鏈
在函式宣告時,生成 JS 內部隱式屬性 [[scope]],該屬性的第 0 位保存全域執行期背景關系 GO 的一個參考
在函式執行前一刻,[[scope]] 第 0 位保存函式執行期背景關系 AO,后一位保存外層函式的 AO,最后保存 GO 參考,如果沒有外層函式,則第 0 位 AO,第 1 位 GO,在尋找宣告時,都會由 0 位向后尋找,即先看自己,再看外層,最后看全域
在函式執行完畢時,從 [[scope]] 中銷毀 AO
function a() { funtion b() { var b = 2; // (3) } var a = 1; // (2) b(); } var c = 3; // (1) a(); // 全域預編譯 // -> GO{c: undefined, a: a(){}} // -> a.SCOPE = [ // GO{c: undefined, a: a(){}} // ] // 全域執行 // 執行 (1) // -> GO{c: 3, z a(){}} // -> a.SCOPE = [ // GO{c: 3, a: a(){}} // ] // 執行到 a(),函式 a 預編譯 // -> a.SCOPE = [ // a_AO{a: undefined, b: b(){}}, // GO{c: 3, a: a(){}} // ] // -> b.SCOPE = [ // a_AO{a: undefined, b: b(){}}, // GO{c: 3, a: a(){}} // ] // 函式 a 執行 // 執行 (2) // -> a.SCOPE = [ // a_AO{a: 1, b: b(){}}, // GO{c: 3, a: a(){}} // ] // 執行到 b(),函式 b 預編譯 // -> b.SCOPE = [ // b_AO{b: undefined}, // a_AO{a: 1, b: b(){}}, // GO{c: 3, a: a(){}} // ] // 執行 (3) // -> b.SCOPE = [ // b_AO{b: 3}, // a_AO{a: 1, b: b(){}}, // GO{c: 3, a: a(){}} // ] // 函式 b 執行完畢,b_AO 銷毀 // -> b.SCOPE = [ // a_AO{a: 1, b: b(){}}, // GO{c: 3, a: a(){}} // ] // 函式 a 執行完畢,a_AO 銷毀 // -> b.SCOPE 銷毀 // -> a.SCOPE = [ // GO{c: 3, a: a(){}} // ]
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/141183.html
標籤:JavaScript
下一篇:vue 專案 甘特圖模塊開發
