保护属性
【1】定义
es5中,对象中的每个属性,不再只是一个简单的值,还有三个相关的开关。
js
eid:{
value:属性值,
writable:true,
enumerable:false,
configurable:false
}
- writable : true/false 控制当前属性值是否可以修改
- enumerable : true/false 控制是否可用for in遍历到这个属性
- configurable : true/false ①控制是否可删除当前属性,②控制是否可修改前两个开关
【2】如何修改开关
1)只修改一个属性的开关
I:
js
Object.defineProperty(对象名,"属性名",{
开关:true或false
... : ...
})
II:强调:今后,只要修改writable和enumerable两个开关时, 都要同时修改configurable:false,阻止别人的程序重新打开我们关闭的开关(configurable:false是不可逆的)
2)修改多个属性的开关
js
Object.defineProperties(对象名,{
属性名1:{
开关名: true或false,
... : ...
},
属性名2:{
开关名: true或false,
... : ...
},
})
示例:
js
var eric={
ename:"艾瑞克",
eage:27
}
Object.defineProperty(eric,"eage",{
// 可以修改eage的值
writable:true,
// 不能让外界for in遍历到
enumerable:false,
// 不可以删除
configurable:false
})
【3】访问器属性
想要灵活的自定义规则保护属性值,三个开关都不适用了。这时候使用访问器属性
1):什么是访问器属性:
自己不保存属性值,只提供对另一个数据属性的保护。------保镖
2):如何定义访问器属性:2步
I:定义小黑屋属性,转移原对象中原属性的值
js
Object.defineProperty(原对象,"小黑屋",{
value:原对象.要保护的属性,
writable:true,
enumerable:false, //小黑屋不能轻易被人发现
configurable:false //小黑屋不可删除
})
II:定义访问器属性(替身+2个保镖)
js
Object.defineProperty(原对象,"要保护的原属性名",{
get:function(){
//this->访问器属性eage所在的当前对象->eric
return this.小黑屋;
},
set:function(value){
if(判断条件){
this.小黑屋=value;
}else{
throw Error("自定义错误提示");//复习第一阶段try catch异常处理
}
},
//访问器属性自己不存值,只提供保护,所以没有value属性
//正是因为writable不好用,我们才被迫用访问器属性代替writable,所以用了get/set,就不用writable。
//因为替身必须替真实属性抛头露面,所以,必须可以被for in发现
enumerable:true,
//因为替身不能随意删除,所以
configurable:false
})
3):外界如何使用访问器属性:和使用对象的普通属性完全一样
I: 获取属性值: 对象.属性名
在底层: 自动调用访问器属性的get()
II: 修改属性值: 对象.属性名=新值
底层: 自动调用访问器属性的set(),将新值传给()中的value形参。
【4】示例:
js
// 访问器属性
var eric={
ename:"艾瑞克",
eage:27
}
// 规定:年龄可以修改,必须在18-65之间
// 定义小黑屋,用于保存真正的属性值
Object.defineProperty(eric,"小黑屋",{
// 值为真正的对象中的属性名
value:eric.eage,
// 可以修改eage的值
writable:true,
// 不能让外界for in遍历到
enumerable:false,
// 不可以删除
configurable:false
})
// 定义替身+2个保镖(get和set)
Object.defineProperty(eric,"eage",{
// get获取小黑屋中真正的值
get:function(){
return this.小黑屋;
},
// set可以将外界想要修改的值传入到小黑屋
set:function(value){
if(value>=18&&value<=65){
this.小黑屋=value;
}else{
throw Error("年龄超出范围");
}
},
// 访问器属性自己不存值,只提供保护,所以没有value属性
// 替身不可以有writable,正是因为writable不好用才使用的访问器属性
// 替身可以for in遍历到
enumerable:true,
// 替身不可以被删除
configurable:false
})
console.log(eric.eage);
eric.eage=30;
console.log(eric.eage);
eric.eage=80;
console.log(eric.eage);
保护结构
3个级别
【1】防扩展
功能:禁止给对象添加新属性
使用:Object.preventExtensions(对象)
问题:只防添加,不防删除
【2】密封
功能:既禁止添加新属性,又禁止删除现有属性
使用:Object.seal(对象)
工作:2件事
1:会自动调用preventExtensions(),先禁止添加
2:会自动遍历对象中每个属性,自动设置每个属性的configurable:false,所有属性禁止删除。
注意:
如果用了seal(),则既不用写preventExtensions(),又不用写所有的configurable:false
问题:属性值目前还是可以修改的
【3】冻结
功能:既禁止添加和删除属性,又禁止修改一切的属性值
使用:Object.freeze(对象)
工作:3件事
1:会自动调用preventExtensions(),先禁止添加
2:会自动遍历对象中的每个属性,自动设置每个属性的configurable:false,所有属性禁止删除
3:会自动遍历对象中每个属性,自动设置每个属性的writable:false,所有属性只读
【4】示例:
js
"use strict";
var eric={
eid:1001,
wname:"艾瑞克",
salary:15000
}
// 保护结构
// 1.防扩展
// 不再允许向eric对象中添加属性
Object.preventExtensions(eric);
// eric._eid=1000;
// console.log(eric._eid);
// 2.密封
// 2件事,不仅不允许向eric中添加属性,也会自动遍历eric的所有属性,并为其添加configurable:false,不允许删除属性
Object.seal(eric);
// delete eric.eid;
// 3.冻结
// 3件事:不仅防扩展,也密封,还自动遍历eric中所有属性,并为其添加writable:false,不允许修改属性值
Object.freeze(eric);
// eric.eid=1003;