定義:函數聲明和變量聲明總是被JavaScript解釋器隱式地提升(hoist)到包含他們的作用域的最頂端。
注意這裡說的是變量或函數的'聲明'會被提升到其作用域頂端
另一個需要注意的是作用域。我們知道Javascript中的作用域只有兩種,一種是全局作用域,一種是函數作用域(局部作用域) 。是沒有塊級作用域等概念的。
下面我們根據這個定義來解釋解釋變量提升這個特性
首先來一段代碼
var x = 'good';
(function () {
console.log(x);
})();
看一下控制台的輸出結果:
good
這一點應該都沒問題吧!聲明一個變量 x 並初始化,然後在匿名函數創建的局部作用域中輸出這個 x。
那如果這樣呢:
var x = 'good';
(function () {
console.log(x);
var x = 10; // 在這裡添加一行對x的定義
})();
發現結果為:
undefined
我們腦補一下過程會覺著這段代碼應該如同之前那段代碼一樣,在console.log的時候輸出原有的 x 的值,而又在其下方重新定義一遍 x 才對,那麼輸出結果也應該和之前一樣才對。為什麼不一樣呢!
這個時候就是變量提升在起作用了,變量提升的定義裡說到變量的聲明會被提升到其作用域最前端。
那就是說我們在這段代碼最後一行的var x = 10
被隱式的做出了調整,var x
實際上被提升到了這段代碼所在作用域(也就是這個匿名函數定義的作用域)的最前面,那就相當於這樣一段代碼:
var x = 'good';
(function () {
var x; // 變量聲明被隱式提升
console.log(x);
x = 10;
})();
如果是這樣一段代碼的話,那就很好解釋了,其 x 在匿名函數定義的作用域中聲明以後覆蓋了全局作用域中的 x ,而這個 x 在這樣一段代碼裡僅僅是聲明有這個 x ,還沒賦值,就被 console.log 掉了,自然輸出結果是 undefined 咯。
那對於函數提升呢!我們可以用這樣一段代碼來理解:
func();
function func() {
console.log('nice');
}
輸出結果:
nice
這段代碼中呢函數的調用時在函數的定義之前。如果按照javascript的規矩,其代碼是按其先後順序一行一行的執行的話,那麼在 func()
做出函數調用的動作的時候,其前面是沒有任何關於func 這一函數的定義的。
這裡之所以能正確調用這個 func 函數,也是由於在整個javascript代碼執行前,其中的函數聲明被提升到了其作用域的最前面,這樣的話在調用func()
函數的時候自然能正確執行而不會出錯。
那以後遇到這樣的代碼 :
(function() {
var x = 10;
var y = 'haha';
var z = 13.6;
})()
那不就是相當於是
(function() {
var x, y, z; // javascript的變量提升機制
x = 10;
y = 'haha';
z = 13.6;
})()
這個特性在書寫javaScript代碼的時候需要多多注意,最好將變量聲明一類的東西就直接寫在其作用域的最開頭,這樣就不會引發一些不必要的錯誤。