Hoisting
指一變數或函式,若在宣告前被使用,會另外再進行一次宣告
引擎在解析原始碼時,會先將所有已宣告的變數提升到程式碼的頂部
並綁定其所屬作用域
變數只會單純宣告,不賦值
code:javascript
var x = 1;
var doSomething = function (y) {
var x; // 示意解析後提昇用
// 由於下面使用的 x=100 裡的 x 未經宣告
// 被 JavaScript 提升至執行序的先頭
console.log(x);
// 因此函式內部的 console.log 會是 undefined
x = 100;
return x + y;
};
console.log(doSomething(50)); // 150
console.log(x); // 1
函式分有存入變數及直接定義的兩種宣告方式
存入變數的函式宣告與變數同樣,只有宣告被提升
直接定義的函式會連同內容一起被提升
code:javascript
square(2);
// 傳入變數式
// 執行結果會為 TypeError: square is not a function
var square = function (number) {
return number * number;
};
// 直接定義式
// 執行結果為正常輸出
function square(number) {
return number * number;
}
若有同名的定義函式和變數
函式的優先權較高,執行結果會是定義函式
這兩種宣告不會被初始化成undefined
加入Hoisting設計的原因
為了達成函式相互歸遞
mutual recursion
避免須以類ML語言的順序撰寫
avoid painful bottom-up ML-like order
實際原理
JavaScript會於執行function時產生一個執行環境
亦有global EC
將所有需要的資訊存在裡面
用以存放宣告的變數、函式和傳入的變數
執行的時候再到VO裡頭查找
依參數、函式和變數的順序放入其中
存進VO時
參數會直接放入
沒有值的話會初始化為undefined
function會新增一屬性放入建立function完後的回傳值
可類比為指向此 function 的指標
已有同名屬性時進行覆蓋
變數會新增一屬性,並賦值為undefined
已有同名屬性時則不會修改該值
let和const多做了一個檢查
皆是在「提升之後」和「賦值之前」的「執行期間」內被存取就會拋出錯誤
Temporal Dead Zone
before excuting your code in the order you wrote it, javascript "pulls up" two types of declarations:
function bla() {}
var bla
to the top of the containing function (or file if you're at top level).
this lets yiu call a function declared this way even if it's defined below.