有个常见的面试题,我们知道,const是es6中新增用于定义常量。但是对于引用类型来说,const 所说的常量,是指,对应的指针或者说地址是常量。那么,如果我们要求,我们定义的数组里面的元素也是不可改变的呢?先来看现象
const a = [1, 2, 3];
console.log(a);
a[0] = 4;
console.log(a)
复制代码
输出是
[1, 2, 3]
[4, 2, 3]
复制代码
可以简单,用const定义的数组,里面的元素是可变的
那么,考虑到,数组其实也是继承于对象,那么,根据下面三个规则
- Object.preventExtendsion(obj) 用来禁止对象可扩展其它属性
- Object.seal(obj)用来禁止对象删除其它属性和扩展其它属性
- Object.freeze(obj)用来冻结对象,就是所有的属性不能够更改和新增
关于Object.preventExtendsion
来看第一种方案
const a = [1, 2, 3, {second: 11}];
console.log(a);
console.log(Object.getOwnPropertyDescriptor(a, 0));
Object.preventExtensions(a); // 开始锁定对象
a[4] = 4;
console.log(a)
console.log(Object.getOwnPropertyDescriptor(a, '1'));
console.log(Object.isExtensible(a));
delete a[0];
console.log(a);
复制代码
输出如下:
[1, 2, 3, [object Object] {
second: 11
}]
[object Object] {
configurable: true,
enumerable: true,
value: 1,
writable: true
}
[1, 2, 3, [object Object] {
second: 11
}]
[object Object] {
configurable: true,
enumerable: true,
value: 2,
writable: true
}
false
[undefined, 2, 3, [object Object] {
second: 11
}]
复制代码
由此可见,preventExtensions可以阻止对象新增属性。但是原对象依旧可以改删其它原有属性,
关于object.seal
const a = [1, 2, 3, {second: 11}];
console.log(a);
console.log(Object.getOwnPropertyDescriptor(a, 0));
Object.seal(a);
a[4] = 4;
console.log(a);
console.log(Object.getOwnPropertyDescriptor(a, '1'));
console.log(Object.isExtensible(a));
delete a[0];
console.log(a);
a[0] = 5;
console.log(a);
复制代码
输出如下:
[1, 2, 3, [object Object] {
second: 11
}]
[object Object] {
configurable: true,
enumerable: true,
value: 1,
writable: true
}
[1, 2, 3, [object Object] {
second: 11
}]
[object Object] {
configurable: false,
enumerable: true,
value: 2,
writable: true
}
false
[1, 2, 3, [object Object] {
second: 11
}]
[1, 2, 3, [object Object] {
second: 11
}]
复制代码
可以看到,configurable已经变成了false,说明是不可以删除的,后面的delete操作也是无效。但是,对象里面的值却是可以更改的
关于Object.freeze
所以,有了以下方案:
const a = [1, 2, 3];
console.log(a);
Object.freeze(a);
a[0] = 4;
console.log(a)
复制代码
输出如下
[1, 2, 3]
[1, 2, 3]
复制代码
由此可见,对象里面的元素也是不可变的
再来试验,如果对应的value不是个简单数据类型呢,比如如下
const a = [1, 2, 3, {second: 11}];
console.log(a);
console.log(Object.getOwnPropertyDescriptor(a, 0));
Object.freeze(a);
a[4] = 4;
console.log(a);
console.log(Object.getOwnPropertyDescriptor(a, '1'));
console.log(Object.isExtensible(a));
delete a[0];
console.log(a);
复制代码
输出如下
[1, 2, 3, [object Object] {
second: 11
}]
[object Object] {
configurable: true,
enumerable: true,
value: 1,
writable: true
}
[1, 2, 3, [object Object] {
second: 11
}]
[object Object] {
configurable: false,
enumerable: true,
value: 2,
writable: false
}
false
[1, 2, 3, [object Object] {
second: 11
}]
复制代码
证明,还是不可变的