簡體   English   中英

JavaScript - 代理集與defineProperty

[英]JavaScript - Proxy set vs. defineProperty

我想構建一個代理來檢測對 object 的更改:

  • 定義了新屬性。
  • 現有屬性已更改。

代碼示例 1 - defineProperty

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 - 設置

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
  • 如何讓代理正確捕獲新屬性的definePropertyset屬性更改?

為什么defineProperty會捕獲屬性變化?

因為當您更改數據屬性(而不是訪問器)時,通過一系列規范步驟,它最終成為 [[DefineOwnProperty]] 操作。 這就是更新數據屬性的定義方式: [[Set]] 操作調用OrdinarySet ,OrdinarySet 調用OrdinarySetWithOwnDescriptor ,OrdinarySetWithOwnDescriptor 調用 [[DefineOwnProperty]],觸發陷阱。

為什么添加 set 會覆蓋 defineProperty?

因為當您添加set陷阱時,您將捕獲 [[Set]] 操作並直接在目標上執行此操作,而不是通過代理。 所以defineProperty陷阱不會被觸發。

如何讓代理正確捕獲新屬性的defineProperty並設置屬性更改?

defineProperty陷阱需要區分何時調用它來更新屬性和何時調用它來創建屬性,這可以通過在目標上使用Reflect.getOwnPropertyDescriptorObject.prototype.hasOwnProperty來實現。

 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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM