JavaScript變數宣告的方式,在ㄚ建剛開始接觸JavaScript時也常常搞不清楚該如何區分並使用它們。
初學JavaScript時常常會遇到這些問題:
- 宣告變數的方式有哪些?
- 宣告變數的方式的特性是什麼?
- var是全域變數嗎?
- 該如何使用?
- 為什麼變數宣告是JavaScript中很重要且基礎的觀念呢?
接下來讓ㄚ建在這裡幫你整理成4大重點,讓你一次搞懂這些問題!
宣告變數與作用域的差別
宣告變數的4種方式
JavaScript的變數可以透過下面4種方法宣告,這些宣告方式可以簡單由全域、函式作用域與區塊作用域劃分。
讓我們一一了解這4種變數宣告的特性與用法吧!
// var 宣告
var dad = "花爸";
// let 宣告
let mom = "花媽";
// const 宣告
const daughter = "橘子";
// 無宣告
son = "柚子";
var宣告
var宣告的變數的作用範圍於函式之中,可以直觀的記憶成var的變數作用於function中。
讓我們從例子了解var的特性吧~
function family_v1() {
var dad = "花爸";
console.log("in family", dad);
}
family_v2(); // => 花爸
try {
console.log(dad);
} catch {
console.log("not found dad");
}
接著看下面例子,如果dad在if的區塊內,我們依然能在整個函式中取的dad的值。
function family_v2() {
if (true) {
var dad = "花爸";
}
console.log(dad);
}
family_v2(); // 花爸
try {
console.log(dad);
} catch {
console.log("not found dad");
}
也可以在函式中重複使用var宣告相同名稱的變數,但要注意變數的值會被覆蓋。
如果在全域範圍宣告var的變數,該變數則作用於全域範圍。
var dad = "花爸";
var dad = "廣志";
console.log("dad", dad); // 廣志
function family_v3() {
console.log("dad", dad);
}
family_v3(); // 廣志
let宣告
let宣告的變數的作域範圍於區塊(block)中,block可以直觀記憶為除了function外的{}中,if與for的{}範圍內皆屬於區塊(block)。
讓我們從例子來了解let的特性吧!
function family_v4() {
if (true) {
let mom = "花媽";
console.log("if 區塊:", mom); // 花媽
}
console.log("函式:", mom); // error
}
family_v4();
例子中的mon只存在於if的區塊(block)內,外部的函示無法獲取mon的值。
記住,let宣告的變數由於作用於區塊(block),因此不同的區塊(block)以let宣告的變數是分別獨立的,不會相互影響。
我們可以從下面的例子了解。
function family_v5() {
let mom = "花媽";
if (true) {
let mom = "美芽";
console.log("if 區塊:", mom); // 美芽
}
console.log("函式:", mom); // 花媽
}
family_v5();
let宣告的變數在同區塊內無法多次宣告。
而宣告的變數會在作用域中因提升(Hoisting)的關係,不會初始化變數,如果變數在宣告前使用,便會造成暫時執行死區。
function family_v6() {
let mom = "花媽";
let mom = "美芽";
console.log(mom); // error
}
family_v6();
// 暫時執行死區
function family_v7() {
console.log(mom); // error
let mom = "花媽";
}
family_v7();
const宣告
const的作用域範圍與let相同皆屬於區塊(block),2者最大的區別便是const宣告的變數無法更新賦值。
const daughter = "橘子";
daughter = "小葵"; // TypeError: Assignment to constant variable.
無宣告
其實JavaScript的變數可以不透過var let const直接宣告!有人可以會想這樣很好啊~可以少打字加快coding速度,但這不是個好主意,因為無宣告的變數,會由內向外尋找變數,如果找不到,則做為全域變數宣告。如果在coding時沒注意到便會發生全域汙染的情形,除了讓程式無法預期執行外,後續debug可是會讓人頭痛的!
function family_v8() {
son = "柚子"
}
family_v8()
console.log("son", son) // 柚子
上面的例子,原本我們預估son作用於函式內,但執行過程中,由於無法在函式內找到son,最終son變為全域變數。
var let差在哪?怎麼用?
var 可以重複宣告,let則不行
var跟let不同,var可以被重複宣告,let重複宣告則會報錯,這部份又會怎麼影響程式的執行呢?,先想想看下面的例子。
var dad = "花爸";
var dad;
conole.log(dad);
接著想想這例子。
var dad = 花爸;
var dad = "廣志";
conole.log(dad);
例子中的情形跟提升有關,變數先被宣告,然後再賦值。重複宣告時,如果不給值,則不會再賦值;若給值,則會被最新的值覆蓋 當撰寫的程式越來越複雜,有時我們可能會忘了曾經宣告的變數,這些小細節累積起來往往招致嚴重後果,而使用let可以避免重複宣告的情形。
for迴圈
接下來我們從這經典的例子,看看var與let的區別。
先看看使用var的for迴圈,想想迴圈的輸出結果?
- 這執行第 0 次, 這執行第 1 次, 這執行第 2 次… 這執行第 4 次
- 這執行第 5 次… (延續 5次)
for (var i = 0; i < 5; i++) {
setTimeout(function () {
console.log('這執行第' + i + '次');
}, 10);
}
答案是2,答對了嗎?為何是這個結果?前面提到var作用域在於整個函式,因此執行5次相當於對i重複宣告五次,並每次將新的i覆蓋上去,導致了都是4次的結果。
var i = 0;
var i = 1;
var i = 2;
var i = 3;
var i = 4;
接著看看使用let的例子。
for (let i = 0; i < 5; i++) {
setTimeout(function () {
console.log('這執行第' + i + '次');
}, 10);
}
let作用於區塊(block)也就是{}內,這時i被鎖在for回圈內,所以得到了正確的結果。
你應當使用let而不是var
let功能與var相近,如果var沒做好管理除了發生變數相互覆蓋,最嚴重的情形便是全域汙染。
Google的JavaScript style guide建議我們應該用const或let宣告區域變數,變數需要重新被賦值才用let,永遠不用var。
有興趣深入了解js的建議寫法可以點此連結
const 特性
修改?不可修改?
在前面介紹const時指出,const被賦予的值無法被修改,既然不能被修改,怎又說可以修改了呢?讓我們先從不可修改的例子來看。
const name = "ㄚ建";
name = "ㄚ明"; // TypeError: Assignment to constant variable.
這部份跟先前const一樣,對const重新賦值會出現錯誤。
接下來看可修改的例子。
當用const宣告陣列或物件時,其內部的屬性是可以被修改的,如下面的例子,arr透過push,obj以obj.name賦予新的值。
const arr = [3, 2, 1];
arr.push(4);
console.log(arr); // [3, 2, 1, 4]
const obj = {
name: "ㄚ建"
};
obj.name = "ㄚ明";
console.log(obj.name); // ㄚ明
對於修改const內部屬性這部分有一點要注意,如果以下面列子的方式修改陣列或物件的內部屬性,對於js引擎來說相當是建立了一個新物件,因此會出現錯誤訊息。
const arr = [3, 2, 1];
arr = ["a", "b", "c"]; // TypeError: Assignment to constant variable.
const obj = {
name: "ㄚ建"
};
obj = {
name: "ㄚ明"
}; // TypeError: Assignment to constant variable.
const總結
- const 變數賦值為常數時,不可修改其值
- const 宣告陣列或是物件時,可修改其內部屬性
變數應當宣告後再使用,避免使用無宣告變數
無宣告變數等於var嗎?
2者之間最大的差別在於是否可以由delete刪除。
說明下,delete是刪除物件某個屬性的語法,詳細資訊可以到MDN了解。
var name = 'ㄚ建';
delete name; // false
website = 'ㄚ建的技能樹';
delete website; // ture
從例子可以了解到無宣告的變數會被當作物件屬性新增,這樣容易在coding時誤刪,讓程式執行時很容易遇到bug,強烈建議你變數一定要先宣告再使用!
結論
阿建幫你把JavaScript的宣告方式總結成表格。
變數範圍整理
變數作用範圍 | 特徵 | |
無關鍵字 | 全域 | 從內到外尋找變數,沒找到則在全域建立變數 可以由delete刪除變數 |
var | 函數內 | 全域範圍使用 var/let 宣告也是全域的 可以被多次宣告 不能由 delete 刪除變數 |
let | 區塊(block) | 全域範圍使用 var/let 宣告也是全域的 有暫時執行死區(TDZ) 不能在宣告前使用 同一作用域不能多次宣告 |
cosnt | 區塊(block) | 全域範圍使用 var/let 宣告也是全域的 有暫時執行死區(TDZ) 不能在宣告前使用 同一作用域不能多次宣告 宣告的變數的值無法再修改 可以更改宣告變數的內部屬性 |
參考資料
JavaScript – The Complete Guide
MDN
淺談 var 與 let 的差異以及有無宣告變數的差異
鐵人賽:ES6 開始的新生活 let, const
如果對文章內容有任何問題或是錯誤,歡迎在底下留言讓我知道: )