我是兵宇,一个始终在coding,始终有创造的程序员。
先想一想:使const定义的对象属性和值也不能改变,相当于静态对象被,我知道
const只能使引用类型的地址不改变,但如何使引用类型对应的的值也不改变呢?
起初想到的是 Object.defineProperty() 能监听到值改变,那我是不是可以使用一些小手段就可以阻止了呢,接着去MDN查看defineProperty 属性 发现有专门的阻止改变值的约束,然后又新发现两种可以约束对象的方式:
- Object.defineProperty()
- Object.freeze()
- Object.seal()
1.Object.defineProperty()、Object.defineProperties()
const object1 = {
"property1": 123
};
Object.defineProperty(object1, 'property1', {
writable: false // 设置不允许写入
});
object1.property1 = 77;
console.log(object1);
// 输出:{property1: 123}
2.Object.freeze()
冻结一个对象,被冻结对象自身的所有属性都不可能以任何方式被修改,新增属性。
But 如果一个属性的值是个对象,则这个对象中的属性是可以修改的,除非它也是个冻结对象。
const object1 = {
"property1": 123,
"property2": {
'key1': 456
}
};
Object.freeze(object1); // 冻结
object1.property1 = 111; // 不会被修改
object1.property2 = 222; // 不会被修改
object1.property3 = 333; // 不会新增
// object1.property3 // undefined
object1.property2.key1 = 666 // 会改变
// object1.property2.key1 // 666
const propKey1 = Object.freeze({'key1': 456})
const object1 = {
"property2": propKey1 // 对象属性也是冻结对象
};
Object.freeze(object1);
object1.property2.key1 = 666 // 不会被改变
// object1.property2.key1 // 456
深冻结函数
// 深冻结函数.
function deepFreeze(obj) {
// 取回定义在obj上的属性名
var propNames = Object.getOwnPropertyNames(obj);
// 在冻结自身之前冻结属性
propNames.forEach(function(name) {
var prop = obj[name];
// 如果prop是个对象,冻结它
if (typeof prop == 'object' && prop !== null)
deepFreeze(prop);
});
// 冻结自身(no-op if already frozen)
return Object.freeze(obj);
}
const obj2 = {
internal: { key: 123 }
};
deepFreeze(obj2);
3.Object.seal()
可以阻止添加属性,删除属性,不能阻止值得修改
const object1 = {
property1: 123
};
Object.seal(object1);
object1.property1 = 456;
// object1.property1 // 123
delete object1.property1; // cannot delete when sealed
// object1.property1 // 123
现在知道如何使对象的属性或值不能改变了吧,最合适的就是通过freeze()封装的深冻结函数使对象为静态的。
4.大部分编译到ES5,那怎么保留这个特性呢?
大家也想一想如何保留此特性呢?
我第一反应是猜想bable要如何转换,确实也没看过编译之后的,想不出来,但我转换一想,如果就是想用这个特性如何实现呢?我要怎么实现呢?这么一想思路就打开了。
先回顾特性:
【 Object.defineProperties():通过配置约束来监听对象的变化】 Object.defineProperties() 是支持ES5的。为什么呢?因为vue2的双向绑定原理就是用到此方法。
【Object.freeze(): 对象 值不能修改、不能删除、不能新增属性】 Object.freeze() 是不是支持ES5不清楚... 但是不是可以通过
Object.defineProperties()+ 某些约束就可以实现吧?真的可以实现么???【Object.seal():可以阻止添加属性,删除属性,不能阻止值得修改】 Object.seal() 是不是支持ES5不清楚... 但是不是也可以通过
Object.defineProperties()+ 某些约束 来实现呢?
看上面的特性,大家还记得 vue2的双向绑定原理的弊端就是不能监听到的新增属性吧,那
Object.freeze()就不能实现。再一次迷茫了
proxy
可是我又又突然想到了vue3使用的 proxy来双向绑定它也是支持ES5的,vue3使用proxy 替换Object.defineProperties()的一个亮点就是能监听到属性的新增、删除,那我就可以使用proxy来实现Object.freeze() 、Object.seal() 对吧。
直接看结果:
看结果是实现了。
反过来我去看看标准答案(ES6转ES5)他们是怎么实现的是否也是这种办法呢?
看效果:(babeljs在线转换)
发现左右两侧怎么是一样的,猜测是支持ES5的,进而看下MDN的说明:
如上说明这些特性是支持ES5的。
扩展:
MDN: Object.defineProperty()
MDN: Object.defineProperties()
MDN: Object.freeze()