has()方法用来拦截HasProperty操作,即判断对象是否具有某个属性时,这个方法会生效。
典型的操作就是in运算符。
let target = {
_name: 'zkf',
name: 'zfk',
}
let hander = {
has(target, key) {
if (key[0] === '_') {
return false
}
return key in target
},
}
let proxy = new Proxy(target, hander)
console.log('_name' in proxy) // false
console.log('name' in proxy) // true
console.log('toString' in proxy) // true 继承的属性依然可以拦截
let target1 = {
_name: '99',
name: '88'
}
Object.seal(target1) //方法封闭一个对象,阻止添加新属性并将所有现有属性标记为不可配置。当前属性的值只要原来是可写的就可以改变
let hander1 = {
has(target, key) {
return false
},
}
let proxy1 = new Proxy(target1, hander1)
console.log('name' in proxy1)
// 'has' on proxy: trap returned falsish for property 'name' which exists in the proxy target as non-configurable
// 代理上的` has `: trap为存在于代理目标中的属性` name `返回假值,该属性是不可配置的
let target1 = {
_name: '99',
name: '88'
}
Object.freeze(target1)
let hander1 = {
has(target, key) {
return false
},
}
let proxy1 = new Proxy(target1, hander1)
console.log('name' in proxy1)
// 'has' on proxy: trap returned falsish for property 'name' which exists in the proxy target as non-configurable
// 代理上的` has `: trap为存在于代理目标中的属性` name `返回假值,该属性是不可配置的
let target1 = {
_name: '99',
name: '88'
}
Object.preventExtensions(target1)
let hander1 = {
has(target, key) {
return false
},
}
let proxy1 = new Proxy(target1, hander1)
console.log('name' in proxy1)
// 'has' on proxy: trap returned falsish for property 'name' but the proxy target is not extensible
// 代理上的` has `:陷阱为属性` name `返回假值,但代理目标不可扩展
上面代码中,obj对象禁止配置或者扩展,结果使用has拦截就会报错。
也就是说,如果某个属性不可配置(或者目标对象不可扩展),则has()方法就不得“隐藏”(即返回false)目标对象的该属性。返回 key in target 或返回 true 均不会报错
另外,虽然for…in循环也用到了in运算符,但是has()拦截对for…in循环不生效
let stu1 = {name: '张三', score: 59};
let stu2 = {name: '李四', score: 99};
let handler = {
has(target, prop) {
if (prop === 'score' && target[prop] < 60) {
console.log(`${target.name} 不及格`);
return false;
}
return prop in target;
}
}
let oproxy1 = new Proxy(stu1, handler);
let oproxy2 = new Proxy(stu2, handler);
'score' in oproxy1
// 张三 不及格
// false
'score' in oproxy2
// true
for (let a in oproxy1) {
console.log(oproxy1[a]);
}
// 张三
// 59
for (let b in oproxy2) {
console.log(oproxy2[b]);
}
// 李四
// 99
上面代码中,has()拦截只对in运算符生效,对for…in循环不生效,导致不符合要求的属性没有被for…in循环所排除。
连带复习的知识点:
使用Object.freeze()冻结的对象中的现有属性值是不可变的。
用Object.seal()密封的对象可以改变其现有属性值。
Object.freeze() 方法可以冻结一个对象。
一个被冻结的对象再也不能被修改;
冻结了一个对象则不能向这个对象添加新的属性,不能删除已有属性,不能修改该对象已有属性的可枚举性、可配置性、可写性,以及不能修改已有属性的值。
此外,冻结一个对象后该对象的原型也不能被修改。freeze() 返回和传入的参数相同的对象