1

我正在尝试为 JavaScript 中的同一目标对象创建多个代理包装器,每个单独的包装器具有稍微不同的属性,这些属性会影响包装功能的运行方式。这些属性分配给和处理程序receiver中的对象并从其访问。但是,当我检查生成的代理时,它们都具有我期望已分配给最后创建的代理的属性集。setget

const obj = {};

const proxies = ['one', 'two'].map(name => {
  console.log(`proxy ${name}`);

  const proxy = new Proxy(obj, {
    get: (target, prop, receiver) => {
      if (prop === 'name') { return receiver.name; }

      return target[prop];
    },
    set: (target, prop, val, receiver) => {
      if (prop === 'name') {
        console.log(`setting name ${val} on receiver`);
        Object.defineProperty(receiver, prop, {
            value: val,
            configurable: true,
            enumerable: true}
        );
      } else {
        console.log(`setting ${prop} ${val} on target`);
        target[prop] = val;
      }

      return true;
    }
  });

  proxy.name = name;

  return proxy;
});

console.log();
console.log(proxies);

我的预期结果:[{name: 'one'}, {name: 'two'}]

实际结果:[{name: 'two'}, {name: 'two'}]。尽管它们看起来相同,但它们并不严格相等。

如果我省略const obj并创建我的对象,new Proxy({}, ...)我会得到预期的结果——一个 proxyone和一个 proxy two,大概是因为目标引用不在它们之间共享。那么:到底是什么?据我了解,使用receiverto storename应该可以防止它被传播到目标对象,但它似乎还是这样做了。

4

2 回答 2

2

你的片段

Object.defineProperty(receiver, prop, {
    value: val,
    configurable: true,
    enumerable: true}
);

不会做(我认为)你期望它做的事情。由于receiverhere 是代理对象,因此属性定义也将通过 to 代理target,这意味着 if/else 中的分支之间的区别几乎没有。如果您希望为每个代理对象存储一个唯一名称,在这种情况下最简单的方法是使用闭包的范围,例如

const proxies = ['one', 'two'].map(name => {
  console.log(`proxy ${name}`);

  const proxy = new Proxy(obj, {
    get: (target, prop, receiver) => {
      if (prop === 'name') { return name; }

      return Reflect.get(target, prop, receiver);
    },
    set: (target, prop, val, receiver) => {
      if (prop === 'name') {
        name = val;
        return true;
      }

      return Reflect.set(target, prop, val, receiver);
    },
    ownKeys: (target) => {
      return Reflect.ownKeys(target).concat('name');
    },
    getOwnPropertyDescriptor: (target, prop) => {
      if (prop === "name") return { enumerable: true, writable: true, configurable: true, value: name };

      return Reflect.getOwnPropertyDescriptor(target, prop);
    },
  });

  return proxy;
});
于 2017-06-10T17:41:37.707 回答
0

直接在代理上设置属性时似乎会发生这种情况。该行为与实例化多个代理无关;创建单个代理并设置它name也会污染目标。

使用继承对象并将其原型设置为代理,如相关问题的答案中所述,不会污染代理的目标。

于 2017-06-10T06:15:09.287 回答