var, let, const多基本的東西

前言

距上次更新已經八個多月,除了工作上學到的新東西,
好像沒有當初自學時的那股衝勁與熱情。
我還是覺得前端的一切很好玩,
但怎麼說呢…

我就懶
圖片來源

有聽人說過,你知道五六年前是沒有前端工程師這職位的,技術變更很快,前端是學不完的,如果只會在原地踏步,三五年後可能也無法生存。
所以我不想耍廢,但也不知道要寫什麼,就從些基本的開始,累積點東西吧!

先說結論

不要用var

現在的工作專案上,已經很少看到var了(至少我工作上沒用過),比起var,盡量使用let、const,可以避免掉全域汙染、重複宣告…等很多不必要的麻煩。

宣告

在程式裡,會大量使用到變數,要使用變數就要先執行宣告。

1
2
3
4
console.log(foo); //'foo is not defined' 沒有被宣告所以不認識
var foo = 10;
// 告訴程式,有一個名為foo的變數產生,並賦予值10
console.log(foo); //10

為什麼用let 不用var

1.全域變數、區域變數

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var a = 10; //全域性作用
let b = 20; //作用在當前區塊的變數

function foo() {
console.log(a);
console.log(b);
}

foo(); // 10, 20

console.log(a); // 10
console.log(b); // 20

console.log(window.a); //10 以瀏覽器為例,全域就是window
console.log(window.b); //undefined

2.block-level scope(塊級作用域)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function foo() {
var a = 10; //存在於函式中
let b = 20;

if(true){
var c = 30; //存在於整個全域,這裡的全域是整個function
let d = 40; //只存在"{}"區塊
console.log(c);//30
console.log(d);//40 存在"{}"中的區塊不會外洩
}

console.log(a); //10
console.log(b); //20
console.log(c); //30
console.log(d); //'d is not defined'
}

foo();

let 是塊級作用域,簡言之,他是存在於”{}”內的,像是if,while…等用到”{}”判斷、迴圈之類的,跟function的函示作用域不同

3.沒有hoising(變量提升)

1
console.log(foo); //'foo is not defined'

剛剛有提到在程式中要用到變數就需要先宣告,我要使用到foo(範例用的變數名稱),如果沒有先宣告的就會會跑出foo is not defined報錯訊息,意思是這個foo並沒有被定義過,程式不認識foo

1
2
3
4
5
var foo;
console.log(foo); //'foo is undefined' 宣告後但沒有值

foo = 10 //賦予foo值
console.log(foo); //10

foo被宣告了以後,就可以取用,不過還沒賦予值的foo會跑出foo is undefined的警告訊息,並不會報錯

如果不按順序宣告呢

1
2
console.log(foo);
var foo;

剛剛學到了要先宣告foo才能取用,不然會出現foo is not defined
結果是
.
.
.

1
2
3
4
console.log(foo); //'foo is undefined'
var foo;
foo = 10
console.log(foo) //10

只要有宣告,就會把變數提升到最上面,不管先後順序都可以呼叫到,這就是hoising變量提升),不過賦值並不會跟著提升。
換作是let呢
.
.
.

1
2
3
4
console.log(foo); //'Uncaught ReferenceError: Cannot access 'foo' before initialization'
let foo;
foo = 10
console.log(foo) //10

這是什麼東東
.
.
.

temporal dead zone, TDZ (暫時性死區)

let沒有hoising(變量提升),使用let時會使區塊形成封閉的作用域,換句話說

在還沒宣告以前都不能使用它

1
2
3
4
5
console.log(foo); //'Uncaught ReferenceError: Cannot access 'foo' before initialization'
let foo;
console.log(foo) //'foo is undefined'
foo = 10
console.log(foo) //10

4.不允許重複宣告

1
2
3
4
var foo = 10;
console.log(foo) //10
var foo = 20;
console.log(foo) //20

foo已經用var宣告過了,又可以重複宣告不會報錯

1
2
3
4
5
let foo = 10; //我在這裡是唯一的foo,不准覆蓋我
foo = 20 // 20 賦值還是可以的
console.log(foo) //10
let foo = 20; // 'foo' has already been declared
var foo = 20; // 'foo' has already been declared

使用let宣告後的變數,如果重複宣告會報錯,因此使用let可以避免掉重複取名覆蓋掉變數的問題。

const

const 特性與let大多相似,但

1.一定要有值

1
2
const myLuckyNumber; //Assignment to constant variable.
const myLuckyNumber = 7;

宣告時一定要賦予值

2.不可重複賦予值

1
2
3
4
const myLuckyNumber = 7
console.log(myLuckyNumber)//7
myLuckyNumber = 8 // Assignment to constant variable'
const myLuckyNumber = 8 // 'myLuckyNumber' has already been declared

const為’常數’,不可重複賦予值與宣告,所以通常是用來放不會變的值,我的幸運數字是’7’不會變。

3.物件依然是參考

1
2
3
4
5
6
7
8
9
const person = {
name: 'Roman',
age: 5,
};


console.log(person.age) //5
person.age = 18;
console.log(person.age) //18

剛剛第二點不是說’不可重複賦予值’,怎麼又可以更改裡面的值,那是因為物件是傳參考(by reference)而非傳值(by value),所以在此依然可以修改屬性

1
2
3
4
5
6
7
8
9
10
11
const person = {
name: 'Roman',
age: 5,
};

const person = { //'person' has already been declared
name: 'Roman',
age: 10,
}

const person = 'Roman'//'person' has already been declared

不能重複指定值、但依然可以修改屬性。

小結

這主題應該是很多人的第一篇文,都看到爛了,但自己實際下來寫感覺又很新奇。
在工作上很多用法都已經習以為常,知道怎麼使用這些宣告,對專案比較好,但如果突然我問我差別或是以上這些東西,一時間還真的會呆滯個幾秒鐘,不知道怎麼解釋,這就是為什麼要自己整理一遍,雖然是基本的東西,但底層越穩健,累積起來對以後整個思考的邏輯會很有幫助。

如果本篇有哪個地方有誤,歡迎指教:)

想看更詳細的解說可以點擊下方參考資料。

參考資料

Summer。桑莫。夏天:ES6: let, const, Block-Level Scope
EddyChang:理解ES6中的暫時死區(TDZ)
坤小:var与let区别-详解块级作用域与局部作用域
卡斯伯:ES6 開始的新生活 let, const