JS-ES6-let變數&const常數

Jordan Tseng
JordanTTCDesign
Published in
8 min readNov 17, 2020

ES6 新語法有很多,第一篇就以先前 JavaScript小學-variable變數 作延伸,介紹 letconst ,為什麼不用 var 就好非要多了解新的語法呢?來看看吧~

為什麼不用 var 改用 let 、const ?

先來看看這兩個 letconst

  • letvar 差不多都是變數,代表值可以做替換
  • const 宣告常數,代表不能在修改,一宣告就固定了

雖然看起來差不多,但是有一個很重要的點是存活範圍不同!!letconst 都是要用來宣告區塊 {} 中的變數意思就是只存活在 {} 中,而使用 var 的話,可能會污染到全域變數,何謂污染🥵?我們用一段 code 來看,包含了一個變數宣告,還有一個 for 迴圈:

var apple = 10
console.log(apple);
for(var i=0 ; i<3 ; i++){
console.log(i);
}
console.log(window);

下圖可以看到在 console 中,宣告的 apple 有在 window 中:

window.apple

可能大家會覺得沒毛病啊,我就是要宣告全域變數,又沒關係,但繼續看下圖的 window 中也出現了 for迴圈 中的 i ,但是當初裡面的 i 只是要用來跑迴圈,不需要他當作一個全域變數,這時候是不是就污染到了!!!

window.i

而程式越來越多,可能就會不小心互相污染了💀💀💀,所以在 ES6 中才會有新的用法~

let 和 const 共同特性

  • 不能重複宣告
let myName = "Jordan";
myName ="Peter";
console.log(myName);
let myName = "Zoe";
console.log(myName);//Identifier 'myName' has already been declared

第二次宣告後會產生 error,這其實有好處,因為以前使用 var 時,重複宣告也沒差,可能沒注意就被蓋過去,而 let 就會看到錯誤。

  • 活在 {} 且階級分明,父層變數可以影響到子層,但是子層變數不能影響到父層:
function varMing () {
var ming = '小明';
if (true) {
var ming = '杰哥';
// 這裡的 ming 依然是外層的小明,所以小明即將被取代
}
console.log(ming); // '杰哥'
}
function letMing () {
let ming = '小明';
if (true) {
let ming = '杰哥';
// 這裡的 ming 是不同的,只有在這個 if block 才有作用
}
console.log(ming); // '小明'
}
function constMing () {
if (true) {
const ming = '杰哥';
// 這裡的 ming 只有在這個 if block 才有作用
}
console.log(ming); // error,找不到
}
varMing();
letMing();
constMing();

由上面可以看到 var 是存活在 function 中,只要同一個 function 中(函式作用域funciton scope),就是同一個,在宣告一次,就會覆蓋掉前一個。

let 呢? 是存活在 () 中括弧 {} 大括號中的(區塊作用域block scop),即便在同一個 function 中,但是不同 {} 內重新宣告的話就不是同一個。letconst 在父層區塊也找不到子層區塊的變數。

當然同級的 function 也管不了,就如同一家公司的設計部經理和開發部經理怎麼能互相管部下:

if (true) {
let a = 'hiA';
console.log(b);//undefined
}
if (true) {
const b = 'hiB'
console.log(a);//undefined
}
  • 在全域 宣告 let 變數時,不會像 var 一樣掛在 window 這個物件上:
var girl = "Zoe";
console.log(window.girl);//var 會出現 "Zoe"
let girl = "Zoe";
console.log(window.girl);//let 會出現 undefined
const girl = "Zoe";
console.log(window.girl);//let 會出現 undefined
  • 沒有 Hoisting 向上提升的功能

之前提到使用 var 宣告變數的時候具備向上提升的功能,所以其實在第一個 console.log() 之前已經先 var a; ,所以才會出現 undefinded。

console.log(a); //undefinded
var a = 1;
console.log(a); //1

但是如果是使用 letconst 會出現 error,因為不會提前,所以其實沒有 a 這個變數😏

Const

constlet 雖然有很多共同特性,但 const 是宣告一個常數,簡單來說就是不可以再做修改的變數,以下面這個範例來說,小明如果使用 const 做宣告,那麼就無法再使用 letconst 做調整了。因為 const 宣告變數主要是用來作唯讀(也就是不能變更的資料,例如: AJAX 的連結)。

const googleUrl = "<https://google.com.tw>";
googleUrl = "<https://yahoo.com.tw>";
console.log(googleUrl);

如果像上面嘗試要改數值,就會變成 error💁

要注意,const 宣告時一定要有值🧐

不過 const 宣告物件與陣列的資料時是可以改變其內容的,假設今天 const 一個物件,然後修改他,會發現內容的值變動了:

const family = {
mom: '老媽',
me: '小明',
sister: '小橙'
};
family.father = '爸爸';
family.mom = '小美';

使用上也能這樣:

const classMate = [];
classMate[0] = 'Jordan';
const jordan = {};
jordan.girl = 'Zoe';

但物件本體不能改:

const jayFamily = {
mom: '杰哥媽',
me: '杰哥'
};
jayFamily = 'fire';
console.log(jayFamily)//TypeError: Assignment to constant variable.

倘若不希望使其資料變動,可以加上一段語法 Object.freeze(),就可以鎖住資料,不會被修改。

let 與 for 迴圈的淵源

為什麼用 let 比用 var 好?剛剛最前面已經提到不會污染到 window,再來舉一個常見的例子,監控列表是否被觸發事件:

var list = document.querySelectorAll('.list li');
var listLen = list.length;
for (var i = 0; i < listLen; i++) {
list[i].addEventListener('click', checkList, false);
}
function checkList() {
console.log(i+1);
}

因為 for迴圈 本身就會自己直接開始執行,而如果裡面的 function 需要事件觸碰的話,就會產生問題,但如果是 let ,他就會在 {} 中每次重新綁定,當然還是要注意 let 的特性,所以 checkList() 要在內部做宣告才行:

var list = document.querySelectorAll('.list li');
var listLen = list.length;
//將 for 迴圈的 var 改成 let
for (let i = 0; i < listLen; i++) {
function checkList() {
alert(i + 1);
}
list[i].addEventListener('click', checkList, false);
}

--

--