Object.freeze、Object.seal、defineProperty关系简介
defineProperty简介
defineProperty即给对象定义属性
语法:Object.defineProperty(obj,property,descriptor)
参数一:obj
绑定属性的目标对象
参数二:property
绑定的属性名
参数三:descriptor
属性描述(配置),且此参数本身为一个对象
- 属性值1:value
设置属性默认值 - 属性值2:writable
设置属性是否能够修改 - 属性值3:enumerable
设置属性是否可以枚举,即是否允许遍历 - 属性值4:configurable
设置属性是否可以删除或编辑 - 属性值5:get
获取属性的值 - 属性值6:set
设置属性的值
功能一:通过value设置属性值
由于Object.defineProperty可以给对象定义属性,我们通过value,可以动态地将obj对象的属性动态地添加给target中。
for (let key in obj){
Object.defineProperty(target,key,{
value: obj[key]
})
}
console.log(target);
功能二:通过writable设置是否可写/修改
1.当writable的值为false时
尝试将count的值从0改为10
writable默认值为false,即不加writable方法,target的值也不可写/修改
for (let key in obj){
Object.defineProperty(target,key,{
value: obj[key],
writable: false
})
}
target.count = 10;//将count中的值0修改成10
console.log(target.count);
// 当writable为false时,无法改变count的值
2.当writable的值为true时
尝试将count的值从0改为10
for (let key in obj){
Object.defineProperty(target,key,{
value: obj[key],
writable: true
})
}
target.count = 10;//将count中的值0修改成10
console.log(target.count);
// 当writable为true时,可以改变count的值
功能三:通过enumerable设置属性值是否允许遍历
在上面的代码基础上,我们添加enumerable属性并尝试遍历target中的属性值
enumerable默认值为false
1.当enumerable的值为false时
for (let key in obj){
Object.defineProperty(target,key,{
value: obj[key],
writable:true,
enumerable: false
})
}
for (key in target){
console.log(key);//遍历target中的属性值并打印,此时结果为空
}
2.当enumerable的值为true时
for (let key in obj){
Object.defineProperty(target,key,{
value: obj[key],
writable:true,
enumerable: ture
})
}
for (key in target){
console.log(key);//成功遍历对象并打印出结果
}
功能四:通过configurable设置属性是否可删
在上面的代码基础上,我们添加configurable属性并尝试用delete方法删除target中的属性
1.当configurable的值为false时
for (let key in obj){
Object.defineProperty(target,key,{
value: obj[key],
writable:true,
enumerable: false,
configurable: false
})
}
delete target.count;//删除count属性
console.log(target); // 显示count属性还在
【注意】configurable默认值为false,即不加configurable方法,target的属性也不可删除
2.当configurable的值为true时
for (let key in obj){
Object.defineProperty(target,key,{
value: obj[key],
writable:true,
enumerable: false,
configurable: true
})
}
delete target.count;//删除count属性
console.log(target); // 成功删除count属性并打印target
功能五:通过get方法获取属性的值
【注意!】当设置get方法时,不能有value和writable方法,否则会报错
get方法的值是一个函数,此函数不需要参数
for (let key in obj){
Object.defineProperty(target,key,{
//value: obj[key],
//writable:true,
enumerable: false,
configurable: true,
get: function(){
return obj[key]
}
})
}
console.log(target.count); // 成功获取到了指定属性(count)的值
【注意】get方法只有在获取指定属性值的时候,才会触发,即调用get下的匿名函数
功能六:通过set方法设置属性的值
set方法的值也是一个函数,定义时会自动注入一个参数,此参数会设置属性的值
for (let key in obj){
Object.defineProperty(target,key,{
//value: obj[key],
//writable:true,
enumerable: false,
configurable: true,
get: function(){
return obj[key]
},
set: function(val){
console.log(val);//打印设置好的值
}
})
}
target.count = 10;//修改count属性的值为10
// 成功修改了指定属性(count)的值
【注意】set方法只有在设置/修改指定属性值的时候,才会触发,即调用set下的匿名函数
target与obj的比较:
- target与obj都是对象,且通过defineProperty方法处理后,二者的值动态相等。
即增加、修改或删除其中任意对象的属性,另一对象也会相应地进行变化。 类似与defineProperty方法将二者以某种方式连在了一起。 - target === obj 的结果为false,即二者并非同一个对象
Object.freeze()
Object.freeze()可以提高性能。
如果有一个对象,里面的内容特别特别多,而且都是一些静态数据,你确保不会修改它们,那你其实可以用Object.freeze()冻结起来,这样可以让性能大幅度提升,提升的效果随着数据量的递增而递增。一般什么时候用呢?对于纯展示的大数据,都可以使用Object.freeze提升性能。
模拟Object.freeze()原理主要用到两个关键方法Object.definedProperty()
、Object.seal()
Object.definedProperty()方法可以定义对象的属性的特性。如可不可以删除、可不可以修改等等
Object.defineProperty(person, 'name', {
configurable: false, // 表示能否通过delete删除属性,能否修改属性的特性...
enumerable: false, // 表示是否可以枚举。直接在对象上定义的属性,基本默认true
writable: false, // 表示能否修改属性的值。直接在对象上定义的属性,基本默认true
value: 'xm' // 表示属性的值。访问属性时从这里读取,修改属性时,也保存在这里。
})
通过上述配置,就能实现不能修改已有属性的值、不能修改已有属性的可枚举性、可配置性、可写性等等功能了
Object.seal()方法可以让对象不能被扩展、删除属性等等。用法:Object.seal(person)
通过Object.seal()方法可以实现不能删除,不能新增对象属性等等功能。通过这两个方法就可以实现一个简单的freeze方法了
function myFreeze(obj) {
if (obj instanceof Object) {
Object.seal(obj);
for (let p in obj) {
if (obj.hasOwnProperty(p)) {
Object.defineProperty(obj, p, {
writable: false
});
myFreeze(obj[p]);
}
}
}
}