Hoisting,常見翻譯是提升或是拉升,這是學習撰寫 JavaScript 程式時相當重要且需要注意的一個直譯語言特性。不了解此特性可能造成閱讀 JavaScript 程式時有所誤解,因此將說明與範例筆記下來。
Hoisting 的作用是,在程式片段中宣告變數以及函數時,JavaScript 會在執行階段,在記憶體中將宣告的變數與函數「移動」到程式片段頂端,
但是在你所撰寫的程式片段依然保持在你所鍵入的位置。因此,若未注意到此一特性,可能會導致程式在預期之外的結果。
以下是一些實際案例展示:
function show(p1, p2) {
return 'x: ' + p1 + ', y: ' + p2;
}
console.log(show('Value X', 'Value Y')); // 結果會是: x: Value X, y: Value Y
這是通常思考上,所想的程式由上而下運行順序。但如果我們將 cosole.log(show(x, y));
寫到程式頂端會發生甚麼事呢?
console.log(show('Value X', 'Value Y')); // 結果還是: x: Value X, y: Value Y
function show(p1, p2) {
return 'x: ' + p1 + ', y: ' + p2;
}
即便是先執行 show 這個函數,但仍然可以得到一樣的結果。這是因為 show 這個函數,被提升到程式片段的頂端處理,之後才執行 cosole.log(show(x, y));
。
同樣的宣告變數也會被提升。現在把上面的程式碼稍作修改,把給 show 的 x 和 y 另外宣告成變數:
var x = 'Value X';
var y = 'Value Y';
function show(p1, p2) {
return 'x: ' + p1 + ', y: ' + p2;
}
console.log(show(x, y)); // 結果會是: x: Value X, y: Value Y
一樣在一般思考的執行順序下,結果會如同預想一樣,顯示出 x 與 y 的內容。現在同樣的把 show 這個函數挪到最頂層,再執行看看結果:
console.log(show(x, y)); // 結果會是: x: undefined, y: undefined
var x = 'Value X';
var y = 'Value Y';
function show(p1, p2) {
return 'x: ' + p1 + ', y: ' + p2;
}
這樣的狀況下,程式不會出現錯誤,但得到結果變成了 undefined。因為提升的關係,其實這段程式碼在執行時,已經變成如同下方程式碼片段:
var x;
var y;
function show(p1, p2) {
return 'x: ' + p1 + ', y: ' + p2;
}
console.log(show(x, y)); // 結果會是: x: undefined, y: undefined
x = 'Value X';
y = 'Value Y';
變成 x 與 y 都沒有給予其初始值,僅有宣告變數,所以得到的結果會是 undefined。
另外,Hoisting 除了在全域範圍(scope)會發生作用之外,於 function { }
的範圍裡也會有作用:
function show() {
var x = 'Value X';
var y = 'Value Y';
console.log('x: ' + x + ', y: ' + y); // 結果會是:x: Value X, y: Value Y
}
show();
將之前的程式改寫成上方的程式片段,執行後可以正確顯示 show 這個函數裡面所宣告的 x 與 y 之值。
同之前的操作範例,若將 console.log
移到最上方執行則:
function show() {
console.log('x: ' + x + ', y: ' + y); // 結果會是:x: undefined, y: undefined
var x = 'Value X';
var y = 'Value Y';
}
show();
執行 show 得到的結果也會是 undefined。
後記補充:
- 於 for 迴圈裡的
var i
也是會受到提升的影響。 - 在 ES6 之後可使用
let
取代var
來限制變數的作用是在當前的 scope 之中。