持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第17天,点击查看活动详情
关于 Object.Freeze()
Object.freeze() 是对象上的内置属性,可以用于冻结一个对象, 常被称为对象冻结;
被冻结的对象具有这些特性:
- 被冻结的对象再也不能被修改;
- 冻结了一个对象则不能向这个对象的属性进行 增 删 改 操作;
- 不能修改已有属性的可枚举性、可配置性、可写性;
- 冻结后返回原对象,不会创建新的对象
- 冻结一个对象后该对象的原型也不能被修改;(注*:虽然说对象原型不能修改,但是通过构造函数创建的对象实例是可以的,具体下面会说)
这里提一下,对象属性默认是可枚举,可配置,可重写的,如果使用
Object.freeze()冻结对象,那么当前对象下 第一层 的属性都变为不可枚举,不可配置,不可改写!
简单使用
首先我们创建一个 obj 对象,用于进行冻结操作
let obj = {
a: 1,
b: 2,
c: {
d: 3
}
}
const fz = Object.freeze(obj);
delete fz.b; // 第一层
fz.a = "AA"; // 第一层
// 第一轮: fz : { a: 1, b: 2, c: { d: 3 } }
delete fz.c.d; // 第二层
fz.c.e = "test"; // 第二层
// 第二轮: fz : { a: 1, b: 2, c: { e: 'test' } }
如上,分别执行了删除与修改操作,我们发现除了第一层不能改,其余的都能改,因为我们上面说了,Object.freeze() 只会冻结第一层,这种我们先称为 浅冻结;类似于浅拷贝(只拷贝第一层的数据,第二层以下的数据还是原对象上的引用)
❗注意: 如果在严格模式下,增删改冻结对象的操作将抛出
TypeErrors
冻结数组
当然,也可以用于冻结数组,不过并不是很常见
let arr = [0, 1];
Object.freeze(arr);
arr[0] = 11; // 默认不能修改
arr.push(2); // 默认不能修改
关于原型与构造函数
前面说了,在被冻结的对象中不能通过原型上进行修改操作,但是通过构造函数创建出来的实例对象是可以被操作的,如下:
function Test() {
this.name = 'shrimpsss';
this.age = 222;
}
const test = new Test();
// 1. freeze 不会返回新的对象
const newTest = Object.freeze(test);
// 2. 通过构造函数原型属性可以增改
Test.prototype.firstName = "MIMO";
// 3. 对象上的属性也是可以改的
test.__proto__.lastName = "Vito";
这样是可以改动的,如下图所示:
ℹ️提示: 但是如果想通过
test.__proto__去修改整个原型上的属性可以吗?抱歉,这种是行不通的,因为实例对象的__proto__也是在第一层
深冻结
现在有个场景,需要冻结该对象自身(不包括原型上)的所有属性;
如果使用递归的方式,我们可以这么做:
先获取当前所有属性的键,再通过遍历当前所有的键,判断是否为对象,如果是则继续遍历下一层,最终返回所有属性都被冻结得雨露均沾的原对象; (如果是普通类型则会略过判断,因为每次执行遍历后冻结的是当前层所有属性,如果有对象类型再进行遍历递归)
Object.DeepFreeze = function (obj) {
// 获取每个对象中的键值 ·1
let _keys = Object.getOwnPropertyNames(obj);
// 判断是否为空
if (_keys.length) {
// 遍历当前层的所有属性
_keys.forEach((key) => {
let _value = obj[key];
// 如果属性是对象的话则继续递归冻结
if (typeof _value === 'object' && _value !== null) {
Object.DeepFreeze(_value);
}
})
}
// 最后返回冻结后的所有对象
return Object.freeze(obj);
}
注意点: 这里使用 getOwnPropertyNames 而不用 Object.keys 去获取键名的原因是,它与 Object.keys 的区别是 getOwnPropertyNames 就算属性不可枚举也可以拿到
我们来查看所有属性描述项(这里通过Object.getOwnPropertyDescriptors 来获取):
const objDfz = Object.DeepFreeze(obj);
Object.getOwnPropertyDescriptors(objDfz);
Object.getOwnPropertyDescriptors(objDfz.c);
// 打印如下 ⬇️:
{
a: { value: 1, writable: false, enumerable: true, configurable: false },
b: { value: 2, writable: false, enumerable: true, configurable: false },
c: {
value: {
d: { value: 3, writable: false, enumerable: true, configurable: false },
e: {
value: { f: 3 },
writable: false,
enumerable: true,
configurable: false
}
},
writable: false,
enumerable: true,
configurable: false
}
}
可以看到已经完全被冻结了,不可配置且不可改写 🤗;
最后如果本文对于本文有疑惑,还请指导勘正 (●'◡'●)