[英]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
?defineProperty
並set
屬性更改?為什么
defineProperty
會捕獲屬性變化?
因為當您更改數據屬性(而不是訪問器)時,通過一系列規范步驟,它最終成為 [[DefineOwnProperty]] 操作。 這就是更新數據屬性的定義方式: [[Set]] 操作調用OrdinarySet ,OrdinarySet 調用OrdinarySetWithOwnDescriptor ,OrdinarySetWithOwnDescriptor 調用 [[DefineOwnProperty]],觸發陷阱。
為什么添加 set 會覆蓋 defineProperty?
因為當您添加set
陷阱時,您將捕獲 [[Set]] 操作並直接在目標上執行此操作,而不是通過代理。 所以defineProperty
陷阱不會被觸發。
如何讓代理正確捕獲新屬性的
defineProperty
並設置屬性更改?
defineProperty
陷阱需要區分何時調用它來更新屬性和何時調用它來創建屬性,這可以通過在目標上使用Reflect.getOwnPropertyDescriptor
或Object.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.