為什麼可以修改使用const宣告的陣列(或物件)的內容?
2021-04-09 14:23 JavaScript
原始問題
以const
宣告一個陣列(或物件),為何可以在宣告完畢後繼續修改該陣列(或物件)的內容?
簡答
const
的限制是「只能賦值一次,不能重新賦值」,不直接等同「不能修改內容」。
環境
Google Chrome: 89.0.4389.114 (Official Build) (64-bit)
os: Windows_NT 10.0.18363 win32 x64
關於const
的事實
You Don’t Know JS Yet 相關筆記
-
const
declared variables are not “unchangeable”, they just cannot be re-assigned.- 不適合以「不能被修改」來理解透過
const
宣告的變數,而是「使用const
宣告的變數只能被賦值一次」
- 不適合以「不能被修改」來理解透過
-
It’s ill-advised to use
const
with object values, because those values can still be changed even though the variable can’t be re-assigned.
- If you stick to using
const
only with primitive values, you avoid any confusion of re-assignment (not allowed) vs. mutation (allowed)! That’s the safest and best way to use const.
ES2015 const is not about immutability 相關筆記
- The only thing that’s immutable here is the binding.
const
assigns a value ({}
) to a variable name (foo
), and guarantees that no rebinding will happen. ES2015 const has nothing to do with immutability of values. - 與其描述為「透過
const
宣告的陣列(或物件)不能被修改內容」,不如將const
理解為「建立一個變數與值之間不變的 binding」。
MDN 上的相關內容
- The value of a constant can’t be changed through reassignment, and it can’t be re-declared.
- 以
const
宣告變數的同時就得賦值
Object.freeze()
- 如果想要確保陣列或物件內容不被修改,可以使用
Object.freeze()
- MDN: Use
Object.freeze()
to make object immutable. A frozen object can no longer be changed; freezing an object prevents new properties from being added to it, existing properties from being removed, prevents changing the enumerability, configurability, or writability of existing properties, and prevents the values of existing properties from being changed. - 一個陣列或物件被凍結後,無法新增或移除該陣列、物件的內容,也不可修改該陣列、物件的 properties
- MDN: Use
Object.freeze()
不會自動套用到巢狀結構內的所有內容上,如以下範例:- 可透過遞迴來凍結巢狀結構物件的內容
Object.seal()
- The Object.seal() method seals an object, preventing new properties from being added to it and marking all existing properties as non-configurable. Values of present properties can still be changed as long as they are writable.
- 與
Object.freeze()
的差異是,經Object.seal()
封閉的物件,不能對其新增或刪除內容,但封閉前就存在的內容可以被修改
- 與
Object.preventExtensions()
Object.preventExtensions()
只會禁止對物件新增內容,但可以刪除或修改既有內容
Object.getOwnPropertyDescriptor()
回傳一物件中某內容的相關設定
參考ECMAScript Specification, Table 3: Attributes of a Data Property:
writable
: If false, attempts by ECMAScript code to change the property’s [[Value]] attribute using [[Set]] will not succeed.writable
若為false
,代表該value
無法被修改- 被
Object.freeze()
凍結的物件,其value
的writable
就被修改為false
enumerable
: If true, the property will be enumerated by a for-in enumeration. Otherwise, the property is said to be non-enumerable.enumerable
為true
代表該value
會被for...in
遍歷
configurable
: If false, attempts to delete the property, change the property to be an accessor property, or change its attributes (other than[[Value]]
, or changing[[Writable]]
to false) will fail.configurable
若為false
,代表該value
無法被刪除- 經
Object.freeze()
或Object.seal()
處理過的物件,其value
的configurable
就被修改為false
補充:無法解凍或再開封
Opposite of Object.freeze or Object.seal in JavaScript
Freezing an object is the ultimate form of lock-down. Once an object has been frozen it cannot be unfrozen – nor can it be tampered in any manner. This is the best way to make sure that your objects will stay exactly as you left them, indefinitely
Object.freeze()
與Object.seal()
是不可逆的程序,一旦一個物件(或陣列)被凍結或封閉,該物件就無法回到凍結(或封閉)前的狀態- 可以透過
Object.assign()
來製作該物件(或陣列)的副本,再修改其內容
參考文件
- You Don’t Know JS Yet: Get Started - 2nd Edition
- ES2015 const is not about immutability
- MDN
- ‘Freezing’ Arrays in Javascript?