點燈坊

失くすものさえない今が強くなるチャンスよ

ECMAScript 之 var

Sam Xiao's Avatar 2020-11-23

var 從 ECMAScript 一開始就存在,也是代表 Keyword,看到 var 就可以判斷是 ECMAScript 了。但 var 在 ECMAScript 2015 之後有了一些改變,重要性也不若以往,TC39 甚至建議完全不要使用 var,改用 letconst

Verson

ECMAScript 5
ECMAScript 2015

Var

宣告變數於 function 內function 外 (global)。

  • Scope:為 execution context,分 function 內與 global,而非以 {} 定 scope
  • Auto Global:若沒 var 一個變數,會自動 升級 成 global 變數 (ES5 ok、但 ES6 廢除)
  • Undefined:有 var 但未指定值,就是 undefined
  • Hoisting:無論你寫在 function 內第幾行,都會在 code 執行 的 creation phase 先宣告變數
  • Redeclaration:若重新 var 一個變數,原來的值仍會存在

Scope

function x() {
  var z = 2
}

x()

console.log(z) // ReferenceError

ES5 與 ES6 都無法執行。

z 的 execution context 為 function 內,所以 function 外部抓不到 z,會在 run-time 跳出 ReferenceError

z = 2

function x() {
  console.log(z)
}

x() // ReferenceError

ES5 可執行,ES6 會噴 ReferenceError

在 ES5 允許 global variable 不使用 var 宣告變數,但 ES6 會啟動 strict mode,儘管是 global variable,也一定要使用 var

Auto Global

function x() {
  y = 1
}

x()

console.log(y) // ReferenceError

ES5 可執行,ES6 會噴 ReferenceError

y 在 ES5 會自動升級為 global 變數,還是會印出 1,但 ES6 會啟動 strict modey 無法升級成 global 變數,會在 runtime 跳出 ReferenceError

Undefined

console.log(x)
console.log('still going...') // RefferenceError

ES5 與 ES6 都無法執行。

Runtime ReferenceError,因為 x 沒有 var 宣告。

var x
console.log(x) // undefined
console.log('still going...') // still going...

ES5 與 ES6 都可執行。

x 只宣告但沒有給值,因此為 undefined

ECMAScript 對於變數,沒有 預設值,也不是 null,而是特有 undefined

Hoisting

console.log(x) // undefined
var x = 2

xconsole.log() 執行完才宣告並定義成 2

實際執行結果為 undefined 而非 ReferenceError

因為 engine 在執行前的 creation phase 會先建立 x,並填入 undefined,此稱為 Hoisting,因此先印出 undefined

var x = y, y = 'A'
console.log(x + y) // undefinedA

因為 var y 會先被 hoisting,所以 x = y 時,y 還是 undefined,因此 x 也是 undefined

Redeclaration

var x = 2;
console.log(x)

var x;
console.log(x)
// 2
// 2

ES5 與 ES6 都可執行。

因此 var x 被 hoisting,所以結果都是 2

var x = 2
console.log(x)

var x = 3
console.log(x)
// 2
// 3

ES5 與 ES6 都可執行。

由於 hoisting 機制,ES5 允許 re-declare。

ES6 在 Babel 可編譯也可執行,但實務上不建議使用 redeclaration

Conclusion

  • 在 ES6 無論 function 內的變數 或 global 變數,一律要使用 var,否則會噴 ReferenceError
  • ECMAScript 有獨特的 undefined,只要變數沒有給定值都是 undefined
  • 雖然 hoisting 允許 re-declare,但實務上不建議使用

Reference

MDN, var