proxy 的has拦截

别兴国
2023-12-01
1、has方法,因何而生

has()方法用来拦截HasProperty操作,即判断对象是否具有某个属性时,这个方法会生效。
典型的操作就是in运算符。

2、Porxy的has拦截。接受两个参数,一个是目标对象,一个是属性key
      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  继承的属性依然可以拦截
3、某些情况下 proxy禁止配置 ( 原对象不可配置或者禁止扩展,这时has()拦截会报错 )
 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 均不会报错

4、值得注意的是,has()方法拦截的是HasProperty操作,而不是HasOwnProperty(自身属性)操作,即has()方法不判断一个属性是对象自身的属性,还是继承的属性,自身属性和继承属性都可以进行一个拦截

另外,虽然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() 返回和传入的参数相同的对象

 类似资料: