ES中保护对象的措施总结
必要性: JS中的对象可随意修改属性值,可随意添加删除属性,太乱,数据安全得不到保障。
如何保护:
保护属性: 保护对属性值的修改
对象属性分为:
命名属性: 可直接用.访问到的属性
数据属性: 直接存储属性值的属性
如何保护: 四大特性:
value: 实际存储属性值
writable: 控制属性是否可修改
enumerable: 控制属性是否可被遍历
仅控制遍历,无法控制用.访问
configurable: 控制是否可删除属性
控制是否可修改其他两个特性
强调: configurable经常作为前两个属性的双保险,且一旦设为false,不可逆!
如果查看四大特性:
Object.getOwnPropertyDescriptor(obj,"属性名")
如何修改四大特性:
Object.defineProperty(obj,"属性名",{
特性:值,
特性:值,
... ...
})
问题: defineProperty一次只能修改一个属性
解决: 同时修改多个属性:
Object.defineProperties(obj,{
属性名:{ 要修改的特性 },
属性名:{ 要修改的特性 },
... : ...
})
问题: 无法使用自定义逻辑保护属性
解决:
访问器属性: 不直接存储属性值
仅提供对其他数据属性的保护
何时: 只要用自定义逻辑保护属性时
如何: 2步:
1. 定义一个隐藏的数据属性实际存储属性值
2. 添加访问器属性保护隐藏的数据属性:
Object.defineProperty(obj,"属性名",{
get(){//在试图获取属性值时自动调用
//返回受保护的数据属性值
},
set(val){//在试图修改属性值时自动调用
//参数val会自动获得要修改的新值
//如果验证val符合规则
//才将val赋值给受保护的属性
//否则
//报错!
},
enumerable:true,
configurable:false
})
如何使用访问器属性: 同普通属性用法完全一致
其中赋值时,自动调用set,取值时自动调get
内部属性: 不能用.直接访问的隐藏属性
__proto__
防篡改: 保护对对象结构的修改
3个级别:
1. 防扩展: 禁止添加新属性
Object.preventExtensions(obj)
原理: 每个obj内部都有一个隐藏属性:
Extensible,默认为true
preventExtensions将obj的Extensible改为false
2. 密封: 在防扩展基础上,进一步禁止删除现有属性
Object.seal(obj)
原理: 修改obj的Extensible为false
将所有属性的configurable都改为false
3. 冻结: 在密封基础上禁止修改任何值
Object.freeze(obj)
原理: 修改obj的Extensible为false
将所有属性的configurable都改为false
还将所有属性的writable都改为false
Object.create(): 可直接用一个父对象创建一个子对象。
如何: var child=Object.create(father,{
自有属性:{
value:值,
writable:true,
enumerable:true,
configurable:true,
},
... : {
...
}
});
强调: 只要添加到对象中的属性,四大特性默认为false,必须显式写为true。
例子:
"use strict"; var emp={ id:1001, //禁止修改 ename:"eric",//禁止删除 salary:12000 //禁止遍历 } //禁止修改id的值 //禁止删除ename: //禁止遍历salary: Object.defineProperties(emp,{ id:{ writable:false, configurable:false }, ename:{configurable:false}, salary:{ enumerable:false, configurable:false } }); // Object.defineProperty(emp,"id",{ // writable:false, // configurable:false//不可逆 // }); // Object.defineProperty(emp,"ename",{ // configurable:false//不可逆 // }); // Object.defineProperty(emp,"salary",{ // enumerable:false, // configurable:false//不可逆 // }); // Object.defineProperty(emp,"id",{ // writable:true, // configurable:true // }); // emp.id=1002; // delete emp.ename; console.dir(emp); for(var key in emp){ console.log(key+":"+emp[key]); } console.log(emp.salary); console.log( Object.getOwnPropertyDescriptor( emp,"id"//ename//salary ) );
"use strict"; var config={ IP:"192.168.0.100", PORT:27017, USER:"admin", PWD:"123456" } Object.freeze(config); //config.PORT=8080; delete config.PORT;
var emp={id:1001,ename:"eric",_age:23}; Object.defineProperty(emp,"_age",{ enumerable:false, configurable:false }); //要求:age必须介于18~65之间 Object.defineProperty(emp,"age",{ get(){ console.log("自动调用get"); return this._age }, set(val){ console.log("自动调用set"); if(val>=18&&val<=65) this._age=val; else throw new RangeError("年龄必须介于18~65之间") }, enumerable:true, configurable:false }); //访问器属性的用法和普通属性完全一致 emp.age++; console.dir(emp); emp.age=-2;
var father={ bal:10000000000, car:"infiniti" } var hmm=Object.create(father,{ phone:{ value:"IPhone 8 Plus", writable:true, enumerable:true, configurable:true }, bao:{ value:"LV", writable:true, enumerable:true, configurable:true } }); console.dir(hmm);