用const定义一个对象,看看和定义简单数据类型有什么不同。
const obj = {
value: 36,
name: 'SUR.E.',
}
console.log(obj)
obj.schoole = 'SYU' // 注意,这里改变了常量对象的内容
console.log(obj)
----------------------------------------------
{value: 36, name: 'SUR.E.'}
{value: 36, name: 'SUR.E.', schoole: 'SYU'} // obj对象被改变了?!
要寻找原因,需要知道JS中的变量和常量是如何存储的。
ES5当中有5种基本数据类型存在于栈内存当中:string 、number、boolean、undefined、null,JavaScript除基本数据类型外,还有引用数据类型,而引用数据类型存在于堆内存当中,而栈内容中存的是引用地址。看下图:
引用数据类型的引用地址不可以被改变,但是地址里存在的内容是可以被改变的。
再来看一下常量的Array,上代码:
const arr = [1, 2, 3]
arr.push(4) // 这里改变值
console.log(arr)
-----------------------
[1, 2, 3, 4] // 可以被改变
如何让常量引用数据类型的内容也不变量呢,要用到Object.freeze()(注意只能冻结一层,下面会详细说什么叫只冻结一层),这个单词的本义是“冻结”,上代码:
const obj = {
value: 36,
name: 'SUR.E.',
}
console.log(obj)
// 开始冻结对象
Object.freeze(obj) // 注意,这里只能传入对象,不能传入数组
obj.schoole = 'SYU' // 注意,这里改变了常量对象的内容
console.log(obj)
----------------------------------------------------------------
{value: 36, name: 'SUR.E.'}
{value: 36, name: 'SUR.E.'} // 没有报错,常量对象的内容也没有被改变
现在来修改一下代码,嵌套一个子对象skill,然后改变它的内容:
const obj = {
value: 36,
name: 'SUR.E.',
skill: {
name : 'code',
year : 10 // ==>注意这里定义的是10
}
}
// 开始冻结对象
Object.freeze(obj) // 冻结
obj.skill.year = 15 // 改为15
console.log(obj)
------------------------------------------
{value: 36, name: 'SUR.E.', skill: {…}}
name: "SUR.E."
skill:
name: "code"
year: 15 // 居然成功了?!
value: 36
所以,freeze()只能冻结当前层的对象,如果想冻结子层对象,还需要再写一行代码:
Object.freeze(obj)
Object.freeze(obj.skill) // 冻结第二层
冻结数据参考:
Object.freeze() - JavaScript | MDN
上面的网站不错,大家可以多看看Web 开发技术 | MDN