首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >JavaScript -代理集与defineProperty

JavaScript -代理集与defineProperty
EN

Stack Overflow用户
提问于 2020-06-13 09:52:31
回答 1查看 2.5K关注 0票数 14

我想构建一个代理来检测对象的更改:

  • 定义了新的属性。
  • 现有属性被更改。

代码示例1- defineProperty

代码语言:javascript
复制
const me = {
  name: "Matt"
}

const proxy = new Proxy(me, {
  defineProperty: function(target, key, descriptor) {
    console.log(`Property ${key} defined.`);
    return Object.defineProperty(target, key, descriptor);
  }
});

proxy // { name: 'Matt' }

proxy.name = "Mark";
// Property name defined.
// Mark

proxy.age = 20;
// Property age defined.
// 20

代码示例1-观测

  • proxy有一个name属性,这正是我所期望的。
  • 更改name属性告诉我已经定义了name不是,而是我所期望的。
  • 定义age属性告诉我已经定义了age;正如我所期望的那样。

代码示例2集

代码语言:javascript
复制
const me = {
  name: "Matt"
}

const proxy = new Proxy(me, {
  defineProperty: function(target, key, descriptor) {
    console.log(`Property ${key} defined.`);
    return Object.defineProperty(target, key, descriptor);
  },
  set: function(target, key, value) {
    console.log(`Property ${key} changed.`);
    return target[key] = value;
  }
});

proxy // { name: 'Matt' }

proxy.name = "Mark";
// Property name changed.
// Mark

proxy.age = 20;
// Property age changed.
// 20

代码示例2-观测

  • proxy有一个name属性,这正是我所期望的。
  • 更改name属性告诉我,name已被更改;正如我所预期的那样。
  • 定义age属性告诉我,age已经更改;不是,而是我所期望的。

问题

  • 为什么defineProperty捕获属性更改?
  • 为什么添加set覆盖defineProperty
  • 如何使代理正确地捕获新属性的defineProperty和属性更改的set
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-06-13 10:07:14

为什么defineProperty捕获属性更改?

因为当您更改数据属性(相对于访问器)时,通过一系列规范步骤,它最终是一个[DefineOwnProperty]操作。这就是如何定义更新数据属性的方法:[[集]]操作调用OrdinarySet,调用调用[DefineOwnProperty]的OrdinarySetWithOwnDescriptor,后者触发陷阱。

为什么增加set覆盖defineProperty?

因为当您添加set陷阱时,您将捕获[Set]操作并直接在目标上执行,而不是通过代理执行。所以defineProperty陷阱不会被触发。

如何使代理正确地捕获新属性的defineProperty并设置属性更改?

defineProperty陷阱需要区分何时调用它来更新属性和何时调用它来创建属性,这可以通过在目标上使用Reflect.getOwnPropertyDescriptorObject.prototype.hasOwnProperty来实现。

代码语言:javascript
复制
const me = {
  name: "Matt"
};

const hasOwn = Object.prototype.hasOwnProperty;
const proxy = new Proxy(me, {
  defineProperty(target, key, descriptor) {
    if (hasOwn.call(target, key)) {
      console.log(`Property ${key} set to ${descriptor.value}`);
      return Reflect.defineProperty(target, key, descriptor);
    }
    console.log(`Property ${key} defined.`);
    return Reflect.defineProperty(target, key, descriptor);
  },
  set(target, key, value, receiver) {
    if (!hasOwn.call(target, key)) {
      // Creating a property, let `defineProperty` handle it by
      // passing on the receiver, so the trap is triggered
      return Reflect.set(target, key, value, receiver);
    }
    console.log(`Property ${key} changed to ${value}.`);
    return Reflect.set(target, key, value);
  }
});

proxy; // { name: 'Matt' }

proxy.name = "Mark";
// Shows: Property name changed to Mark.

proxy.age = 20;
// Shows: Property age defined.

这有点不合时宜,但它会让你朝着正确的方向前进。

您可以只使用一个set陷阱来完成它,但是这不会被任何直接到[DefineOwnProperty]而不是通过[Set,例如Object.defineProperty )的操作触发。

票数 14
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62358094

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档