使用 let 宣告變數

ECMAScript 2015 是 JavaScript 歷史上最重要的一次升級,也讓 JavaScript 終於趕上主流程式語言的高度,若要明顯的分辨 ES5 與 ES6,最明顯的方式的方式就是看有沒有使用 let

Verson


ECMAScript 2015

Let


宣告變數於 block {} 內。

var 宣告變數於 function 內或 function 外 (global)

Scope


scope01.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function varTest() {
var x = 1;

if (true) {
var x = 2;
console.log(x);
}

console.log(x);
}

varTest();
// 2
// 2

ES5 與 ES6 都可執行。

實際執行為

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function varTest() {
var x;
x = 1;

if (true) {
x = 2;
console.log(x);
}

console.log(x);
}

varTest();
// 2
// 2

因為 Hoisting,var x 被移到最上層,scope 為 function 內,因此離開 if (true) 仍然為 2

scope02.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function letTest() {
let x = 1;

if (true) {
let x = 2;
console.log(x);
}

console.log(x);
}

letTest();
// 2
// 1

ES5 沒有 let 無法執行。

第 4 行

1
2
3
4
if (true) {
let x = 2;
console.log(x);
}

使用 let 後,其 scope 為 block {},只有在 {}2,離開 {} 就變回 1

以主流程式語言而言,變數的 scope 都是 block {},而非 function,因此 ECMAScript 的 let 較符合大家的習慣,如此就可如 C# 一樣,將變數宣告在程式碼要用的地方,而不是宣告在 function 最前面,因此 TC39 建議全面使用 let 取代 var

scope03.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var a = 1;
var b = 2;

if (a === 1) {
var a = 11;
let b = 22;

console.log(a);
console.log(b);
}

console.log(a);
console.log(b);
// 11
// 22
// 11
// 2

第 9 行

1
console.log(b);  // 22

因為 let b = 22,為 block level。

13 行

1
console.log(b); // 2

因為 var b = 2,為 global level。

scope04.js

1
2
3
4
5
6
7
8
function foo(cnt) {
for(var i = 0; i < cnt; i++) {
}
console.log(i);
}

foo(5);
// 5

var 為 function level,因此 for loop 執行完還存在。

scope05.js

1
2
3
4
5
6
7
8
function foo(cnt) {
for(let i = 0; i < cnt; i++) {
}
console.log(i);
}

foo(5);
// ReferenceError

let 為 block level,超出 for loop 就抓不到了。

for loop 應全面使用 let 避免 Side Effect

scope06.js

1
2
3
4
5
6
7
var x = 'global';
let y = 'global'

console.log(window.x);
console.log(window.y);
// global
// undefined

varlet 雖然都可建立 global 變數,但 var 會污染 DOM 的 window object,但 let 不會。

若要使用 global 變數,應全面使用 let 取代 var

Redeclaration


redeclaration01.js

1
2
3
4
5
6
7
var x = 2;
console.log(x);

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

ES5 與 ES6 都可以執行。

var 允許對變數重複宣告。

redeclaration02.js

1
2
3
4
5
6
let x = 2;
console.log(x);

let x = 3;
console.log(x);
// SyntaxError

ES5 與 ES6 都無法執行。

let 不允許對變數重複宣告。

redeclaration03.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function foo(x) {
switch(x) {
case 0:
var y = 2;
console.log(y);
break;
case 1:
var y = 3;
console.log(y);
break;
}
}

foo(1);
// 3

ES5 與 ES6 都可執行。

實際執行時

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function foo(x) {
var y;

switch(x) {
case 0:
y = 2;
console.log(y);
break;
case 1:
y = 3;
console.log(y);
break;
}
}

foo(1);
// 3

因為 var 會 Hoisting,所以允許 redeclaration。

redeclaration04.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function foo(x) {
switch(x) {
case 0:
let y = 2;
console.log(y);
break;
case 1:
let y = 3;
console.log(y);
break;
}
}

foo(1);

若將 var 改成 let,則 ES5 與 ES6 都無法執行。

因為 let 認 {} 為 scope,不允許 redeclaration。

redeclaration05.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function foo(x) {
switch(x) {
case 0: {
let y = 2;
console.log(y);
break;
}
case 1: {
let y = 3;
console.log(y);
break;
}
}
}

foo(1);

在每個 case 加上 {},則可以 redeclaration。

Conclusion


  • var 為 function level 或 global level;而 let 為 block level
  • var 的 global 變數會污染 DOM 的 window object,但 let 不會
  • 實務上建議全面使用 let 取代 var

Sample Code


完整的範例可以在我的 GitHub 上找到

Reference


MDN JavaScript, let

2018-09-27