2

get以下代码包含对象中带有陷阱的代理__proto__。从对象中获取某个属性时,根据js逻辑,只有当对象本身不包含相应属性时才会调用trap。因此,在分配后,属性出现在对象中并且不会调用 get 陷阱。它完全按照我的意愿工作。

var x = Object.create(new Proxy({}, {
  get(obj, key) {
    if (typeof key !== 'symbol') {
      console.log('Reading a nonexisting property: ' + key);
    }
  }
}));

var temp;
console.log(1, Object.prototype.hasOwnProperty.call(x, 'a'));

temp = x.a;
console.log(2, Object.prototype.hasOwnProperty.call(x, 'a'), temp);

temp = x.a;
console.log(3, Object.prototype.hasOwnProperty.call(x, 'a'), temp);

x.a = 12;
console.log(4, Object.prototype.hasOwnProperty.call(x, 'a'));

temp = x.a;
console.log(5, Object.prototype.hasOwnProperty.call(x, 'a'), temp);
.as-console-wrapper.as-console-wrapper { max-height: 100vh }

现在我要添加一个set陷阱:

var x = Object.create(new Proxy({}, {
  get(obj, key) {
    if (typeof key !== 'symbol') {
      console.log('Reading a nonexisting property: ' + key);
    }
  },
  set(obj, key, val, receiver) {
    console.log('Assigning a property: ' + key);
    Reflect.set(obj, key, val); // Inside of proxy, not outside
    //Reflect.set(receiver, key, val); // Infinite recursion
    return true;
  }
}));

var temp;
console.log(1, Object.prototype.hasOwnProperty.call(x, 'a'));

temp = x.a;
console.log(2, Object.prototype.hasOwnProperty.call(x, 'a'), temp);

temp = x.a;
console.log(3, Object.prototype.hasOwnProperty.call(x, 'a'), temp);

x.a = 12;
console.log(4, Object.prototype.hasOwnProperty.call(x, 'a'));

temp = x.a;
console.log(5, Object.prototype.hasOwnProperty.call(x, 'a'), temp);
.as-console-wrapper.as-console-wrapper { max-height: 100vh }

问题是我不能将属性直接写入对象。该属性要么写入被代理包装的对象而不是包装代理的对象,要么发生无限递归set陷阱。

所以我想获得与第一个片段相同的输出,但使用 new line Assigning a property: a

PS:俄语中的相同问题。

4

1 回答 1

3

要实际创建属性,您必须使用Object.defineProperty(或者Reflect.defineProperty,如果您愿意)。只是通过赋值来设置属性,或者Reflect.set确实会遍历原型链,所以当你在原型(或代理陷阱)的 setter 中对对象执行此操作时,你总是会得到递归。

您可以使用

new Proxy({}, {
  get(target, key) {
    if (typeof key !== 'symbol') {
      console.log('Reading a nonexisting property: ' + key);
    }
  },
  set(target, key, val, receiver) {
    console.log('Assigning a property: ' + key);
    return Reflect.defineProperty(receiver, key, {
      value: val,
      writable: true,
      enumerable: true,
      configurable: true
    });
  }
});

完整代码:

var x = Object.create(new Proxy({}, {
  get(obj, key) {
    if (typeof key !== 'symbol') {
      console.log('Reading a nonexisting property: ' + key);
    }
  },
  set(obj, key, val, receiver) {
    console.log('Assigning a nonexisting property: ' + key);

    return Reflect.defineProperty(receiver, key, {
      value: val,
      writable: true,
      enumerable: true,
      configurable: true
    });
  }
}));

var temp;
console.log(1, Object.prototype.hasOwnProperty.call(x, 'a'));

temp = x.a; // get trap
console.log(2, Object.prototype.hasOwnProperty.call(x, 'a'), temp);

temp = x.a; // get trap
console.log(3, Object.prototype.hasOwnProperty.call(x, 'a'), temp);

x.a = 12;   // set trap creates a property and sets it
console.log(4, Object.prototype.hasOwnProperty.call(x, 'a'));

temp = x.a; // direct read - no traps
console.log(5, Object.prototype.hasOwnProperty.call(x, 'a'), temp);

x.a = 42;   // direct write - no traps
console.log(6, Object.prototype.hasOwnProperty.call(x, 'a'));

temp = x.a; // direct read - no traps
console.log(7, Object.prototype.hasOwnProperty.call(x, 'a'), temp);
.as-console-wrapper.as-console-wrapper { max-height: 100vh }

于 2017-10-11T12:07:45.893 回答