# 變數

# letconst

let 被稱作為變數對應的值會產生變動,與其相對的是 const 即為常數對應的值不能再變動。

letconst 是 ES6 新增的語法,在環境允許的狀況下,這兩者會被優先使用。

JS 在紀錄變數上採取的是動態定型語言,變數本身沒有型態資訊,運用變數型態不須特別宣告。因此,x 的值由數字轉為字串也不會出錯。

> let x = 200
undefined
> x = 'Zrn Ye'
'Zrn Ye'
>

動態定型語言界中流行鴨子定型 (Duck typing):
「如果他走路像個鴨子,游泳像個鴨子,叫聲像鴨子,他就是鴨子。」

對基本型態來說,變數存了指定的值。
對複合型態來說,變數始終是個參考值,指定運算改變的是變數的參考對象。
因此,我們可以這麼做:

REPL
> let arr1 = [10,20,30]
undefined
> let arr2 = arr1
undefined
> arr1[0] = 100
100
> arr2
[ 100, 20, 30 ]
>

對於 const 而言,宣告的常數只是不能重新設定該名稱的參考物件
如果物件可變動,物件依舊可以變動

REPL
> const arr = [ 1, 2, 3 ] 
undefined
> arr[0] = 10
10
> arr
[ 10, 20, 30 ]
>

如果沒有使用 letconst 先行宣告的話,會導致 ReferenceError ,表示變數尚未宣告

使用 let 時,若該變數已經存在,會發生 SyntaxError

REPL
> console.log(x)
Uncaught ReferenceError: x is not defined
> let y = 1000
undefined
> let y
Uncaught SyntaxError: Identifier 'y' has already been declared
>

如果宣告了變數但未給其定值,會給予 undefined 當作回傳值。

REPL
> let z
undefined
> z
undefined
>

# var

在比 ES6 更早之前的版本,並沒有 constlet ,宣告皆為 var ,他有個古怪的個性:若原始檔案中儲存了以下程式碼也並不會出錯。

console.log(m);
var m = 10;
console.log(m);

運行結果為:

undefined
10

var 在宣告前後範圍內都是有效的,這種行為被稱為提升。
絕大多數情況下,你不會希望有提升行為。如果是使用 let 就能避免:

console.log(m); //ReferenceError: Cannot access 'm' before initialization
let m;

嚴格來說,使用 let 也會有提升行為,被稱作暫時死區。

# undefinednull

使用 letvar ,若宣告變數為定義值,變數會被賦予 undefined
若取得物件上不存在,也會回傳 undefined
undefined 使用 typeof 的結果是 'undefined' ,對 undefined 本身等於 undefined :

> let x;
undefined
> x
undefined
> typeof undefined
undefined
> x === undefined
true
>

在 JS 世界中, undefined 並非保留字喔,所以是可以被宣告跟定值的。

在 JS 世界裡還有一個怪值,稱作 null 。代表沒有物件
舉個例子:若有變數本身是參考某個物件,若後來不想在那麼做,可以令變數參考 null :

> let obj = {x: 10};
undefined
> obj = null;
null
>

但會這麼做的機會不多,比較常見的情況是透過 API 想找某條件的物件,而沒有找到時回傳 null ,這類 API 在瀏覽器中很多。

null 使用 typeof 會得到 'object' ,對於 null 也不能做任何的操作。
試圖存取 null 或呼叫方法,會引發 TypeError

# 嚴格模式

ES5 增加了嚴格模式,啟用嚴格模式後,若誤用了不好或早期規範不清的特性,會發生直譯或執行等相關錯誤。

JS 可以不使用 varlet 等宣告變數,例如:

x = 10;
console.log(x); // 顯示 10

然而,這不是個好特性,因為其宣告就會變成全域變數,絕大情況應該要避免。

因此,若在 .js 檔案的開頭加上 use strict 字串,即可避免此行為。

use strict

x = 10; //ReferenceError: x is not define
console.log(x);

也可以在某些函式中使用嚴格模式,方式是在函式的本體開始處加上 use strict :

function foo(){
    'use strict'
    // 其他程式碼
}

嚴格模式下,有許多被禁止的行為。

例如,ES6 規範中可以用 0o7 代表八進位整數,但在之前的版本你只需要在數字前加上 0 就可以表示八進位。若啟用了嚴格模式就會引起 SyntaxError

另外,如果要用 delete 刪除物件,失敗的話,會直接產生 TypeError

在嚴格模式下,不能使用保留字當作變數名稱,誤用的話,會引發 SyntaxError

還有許多嚴格模式下的限制,可以參考這個網站

除了避免錯誤外,嚴格模式也能加速運行程式的效能。

在使用 Node.js 的指令時,有個 --use_strict 選項可以開啟嚴格模式,適用於 REPL。

提示命令字元
C:\Users\user\Desktop\js> node --use_strict
Welcome to Node.js v14.15.4
Type ".help" for more information.
> let arr = [1, 2, 3];
undefined
> delete arr.length
Thrown:
TypeError: Cannot delete property 'length' of [object Array]

# 參考資料

JavaScript 技術手冊

更新於 閱讀次數

用實際行動犒賞爆肝的我😀

Zrn Ye LinePay

LinePay