JavaScript語言特性:變數拉升Variable Hoisting

Posted by JSON on March 5, 2014

變數拉升(Variable Hoisting)是JavaScript的語言特性, 可幫助我們理解在某些情況Bug是怎麼發生的。

下面這兩段代碼,第一段代碼發生了錯誤,因為沒有宣告變數就使用了; 第二段代碼看似宣告前就先使用變數,卻沒有發生錯誤,這就是變數拉升所造成地:

(function a(){ console.log(j);})() // 引發錯誤:Uncaught ReferenceError: j is not defined
(function a(){ console.log(j); var j; })() // 不會出錯

JavaScript區域變數的可視範圍(Scope)為Function Scope,而非Block-scoped, 但JavaScript又允許你在任一地方使用var宣告變數,因此變數拉升(Variable Hoisting) 這件事情就偷偷地幫你做了。

了解變數宣告行為最好的方法就是看成兩個部分:

  1. 宣告
  2. 指定

例如將var i = 5;解讀成:

var i;
i = 5;

變數拉升就是會隱性的將宣告部分拉升到外圍函式的頂端,將指定部分留在原地,例如:

function f() {
  console.log(i);
  if(true) {
    var i = 123;
  }
}

經過變數拉升可看成:

function f() {
  var i;
  console.log(i);
  if(true) {
    i = 123;
  }
}

這也是為什麼console.log能在if statement之前就能使用i的原因,但印出的結果是undefined。

對於JavaScript區域變數不會是Block-scoped的唯一例外發生在,try catch

(function f(){
  var exception = "no exception";
  try {
    throw "exception";
  } catch(exception) {
    console.log(exception); // 印出 "exception"
  }
  console.log(exception); // 印出 "no exception"
})()

變數拉升這件事情,變成自己手動來做,可撰寫出更易閱讀的程式碼,把它養成好習慣吧! 另外變數拉升似乎是JavaScript面試常會遇到的題目,當然不會告訴你這一題在考變數拉升, 而是會給你一段代碼,問你會印出什麼或者a跟b分別會是什麼之類的題目,不理解變數拉升就很容易掉入陷阱