文章目录
一、ES5之保护对象:
在ES5中,为对象提供了一套保护自身的机制
对象中的每个属性,不仅是一个简单的值,底层已经变成了一个缩微的小对象。
1.自带的三个保护属性
例如,value = “1”,底层包含以下三个常用属性,可看作三个开关:
属性 | 作用 |
---|---|
writable: true | 控制是否可修改当前属性值 |
enumerable: true | 控制是否可用for in遍历到这个属性 只防"for in",不防"." |
configurable: true | 1.控制是否可删除当前属性 2.控制是否可修改前两个开关! 一旦改为false,不可逆! |
2.修改属性的开关:
2.1 修改单个属性
只要修改writable和enumerable两个开关时,必须同时修改configurable:false,阻止别人的程序重新打开我们关闭的开关。
模板:
Object.defineProperty(对象名, "属性名", {
开关:true或false,
... : ...
})
示例:
var erya={
eid:1,
ename:"二雅",
salary:1022
}
Object.defineProperty(erya, "eid",
// eid禁止修改——只读
{
writable:false,
configurable:false //双保险
}
})
2.2 修改多个属性
模板:
Object.defineProperties(对象名, {
属性名1:{
开关名: true或false,
... : ...
},
属性名2:{
开关名: true或false,
... : ...
},
})
示例:
var erya={
eid:1,
ename:"二雅",
salary:1022
}
// 修改多个属性开关
Object.defineProperties(erya,{
// ename禁止删除
ename:{
configurable:false
},
//salary禁止随意用for in循环遍历
salary:{
enumerable: false, //半隐藏
configurable:false
}
})
2.自定义规则-访问器属性
访问器属性定义:自己不保存属性值,只提供对另一个数据属性的保护——保镖
2.1 定义访问器属性
1) 定义小黑屋属性,转移原对象中原属性的值
Object.defineProperty(原对象,"小黑屋",{
value:原对象.要保护的属性,
writable:true,
enumerable:false, //小黑屋不能轻易被人发现
configurable:false //小黑屋不可删除
})
2) 定义访问器属性替身+2保镖(get_set)
Object.defineProperty(原对象,"要保护的原属性名",{
//保镖一:获取外界的信息
get:function(){
//this->访问器属性eage所在的当前对象->eric
return this.小黑屋;
},
//保镖二:将信息返回到外界
set:function(value){
if(判断条件){
this.小黑屋=value;
}else{
throw Error("自定义错误提示");//复习第一阶段try catch异常处理
}
},
2.2 外界使用访问器属性
和使用对象的普通属性完全一样:
1) 取值: 对象.属性名
底层: 自动调用访问器属性的 get()
2) 修改: 对象.属性名=新值
底层: 自动调用访问器属性的 set(),将新值传给()中的value形参。
示例: 使用访问器属性保护年龄属性:
var erya={
ename:"二雅",
eage:20
}
//eage可修改,18~65
//1. 定义小黑屋属性,转移原对象中原eage属性值
Object.defineProperty(erya,"小黑屋",{
value:erya.eage,
writable:true,
enumerable:false,
configurable:false
})
//2. 定义访问器属性替身+2保镖
Object.defineProperty(erya,"eage",{
//访问器属性自己不存值,只提供保护,所以没有value属性
// 保镖一:
get:function() {
console.log(`eage自动调用了自己的get(),返回${this.小黑屋}给外部`)
//this->访问器属性eage所在的当前对象->eric
return this.小黑屋;
},
set:function(value) {
console.log(`eage自动调用了自己的set(),接收外部传入的新值${value}`);
if (value>=18&&value<=65) {
this.小黑屋=value;
} else {
throw Error("年龄超范围!");
}
},
//正是因为writable不好用,我们才被迫用访问器属性代替writable,所以用了get/set,就不用writable。
//因为替身必须替真实属性抛头露面,所以,必须可以被for in发现
enumerable:true,
//因为替身不能随意删除
configurable:false
})
//外界试图获得erya的eage值
console.log(erya.eage);
//外界试图修改erya的eage属性
erya.eage=26;
//外界试图获得erya的eage值
console.log(erya.eage);
//外界试图修改erya的eage属性
erya.eage=-2;//抛出异常
2.3 访问器中的this
访问器属性中的this->访问器属性所在的当前对象
3.保护结构
a. 防扩展
禁止给对象添加新属性
Object.preventExtensions(对象)
b. 密封
既禁止添加新属性,又禁止删除现有属性
Object.seal(对象)
i. 会自动调用preventExtensions()
,先禁止添加
ii. 会自动遍历对象中每个属性,自动设置每个属性的configurable:false
,所有属性禁止删除。
tip:
1.用seal()
,既不用写preventExtensions()
,又不用写所有的configurable:false
。
2. seal()
虽然不能添加删除属性,但可以修改属性值。
3. 一般,保护到密封级别就够了!
c.冰冻
既禁止添加删除属性,又禁止修改一切属性值。
Object.freeze(对象)
i. 会自动调用preventExtensions()
,先禁止添加
ii. 会自动遍历对象中每个属性,自动设置每个属性的configurable:false
,所有属性禁止删除。
iii. 会自动遍历对象中每个属性,自动设置每个属性的writable:false
,所有属性只读
示例:
var erya={
eid:1,
ename:"二雅",
salary:1022
}
Object.defineProperties(erya, {
eid:{ writable:false },
salary:{ enumerable:false }
})
//防扩展:
Object.preventExtensions(erya);
//密封: (够了)
Object.seal(erya);
//冻结: (过于严格)
Object.freeze(erya);