![](/img/trans.png)
[英]How to check if a property of an object is a getter or a setter?
[英]How to observe changes to contents of an object's array property exposed through setter-getter or Proxy
我正在創建如下的IIFE。 它將getter和setter返回到內部存儲的數組變量。 我希望攔截對該數組所做的更改console.log
旨在在下面的設置器中表明這一點。
const a = (function() {
let arr = [];
return {
get arr() {return arr},
set arr(v) {
console.log("new arr", v);
arr = v;
},
}
})();
如果我完全重新分配arr
,例如a.arr = [1, 2]
,則此方法很好。
但是它不會攔截對數組內容所做的更改,例如a.arr.push(3)
或a.arr.shift()
。
尋找有關如何攔截這些內容更改的任何想法。
這是使用新的Proxy對象的替代嘗試:
a = (function() {
let details = {
arr: []
}
function onChangeProxy(object, onChange) {
const handler = {
apply: function (target, thisArg, argumentsList) {
onChange(thisArg, argumentsList);
return thisArg[target].apply(this, argumentsList);
},
defineProperty: function (target, property, descriptor) {
Reflect.defineProperty(target, property, descriptor);
onChange(property, descriptor);
return true;
},
deleteProperty: function(target, property) {
Reflect.deleteProperty(target, property);
onChange(property, descriptor);
return;
}
};
return new Proxy(object, handler);
};
return onChangeProxy(details, (p, d) => console.log(p, d));
})();
問題仍然存在。 仍然無法使用從a.arr[0] = 1
到a.push(3)
任何內容觀察對a.arr
內容所做的更改。
解決方案基於Kris在Sindre的“ on-change”庫中的 提交 。
解決方案的解釋 ,由Kris撰寫:
在
set
陷阱中,我的目標是確定所提供的值是否是先前調用get
陷阱所產生的Proxy
。 如果是這樣的Proxy
,則任何屬性訪問都將被我們自己的get
陷阱攔截。 因此,當我訪問value[proxyTarget]
將調用我們的get
陷阱,當property === proxyTarget
時,該陷阱將被編碼為返回target
(第46行)。 如果傳遞給set
的值不是基於變更創建的代理,則value[proxyTarget]
是undefined
。
解決方案的完整代碼:
(object, onChange) => {
let inApply = false;
let changed = false;
function handleChange() {
if (!inApply) {
onChange();
} else if (!changed) {
changed = true;
}
}
const handler = {
get(target, property, receiver) {
const descriptor = Reflect.getOwnPropertyDescriptor(target, property);
const value = Reflect.get(target, property, receiver);
// Preserve invariants
if (descriptor && !descriptor.configurable) {
if (descriptor.set && !descriptor.get) {
return undefined;
}
if (descriptor.writable === false) {
return value;
}
}
try {
return new Proxy(value, handler);
} catch (_) {
return value;
}
},
set(target, property, value) {
const result = Reflect.set(target, property, value);
handleChange();
return result;
},
defineProperty(target, property, descriptor) {
const result = Reflect.defineProperty(target, property, descriptor);
handleChange();
return result;
},
deleteProperty(target, property) {
const result = Reflect.deleteProperty(target, property);
handleChange();
return result;
},
apply(target, thisArg, argumentsList) {
if (!inApply) {
inApply = true;
const result = Reflect.apply(target, thisArg, argumentsList);
if (changed) {
onChange();
}
inApply = false;
changed = false;
return result;
}
return Reflect.apply(target, thisArg, argumentsList);
}
};
return new Proxy(object, handler);
};
這解決了我的問題,而無需借助檢查數組修改方法的技巧。
在David Walsh在這里的帖子的幫助下,到目前為止,我已經對此進行了排序。 它仍然很難看,但是現在可以使用。
更新了具有遞歸式get
陷阱的onChanged
Proxy maker。
get: function (target, property, receiver) {
let retval;
try {
retval = new Proxy(target[property], handler);
} catch (err) {
retval = Reflect.get(target, property, receiver);
}
if (mutators.includes(property))
onChange(target, property, receiver);
return retval;
},
還添加了用於檢查獲取陷阱的函數列表(丑陋,hacky):
const mutators = [
"push",
"pop",
"shift",
"unshift",
"splice",
"reverse",
"fill",
"sort"
]
到目前為止,這似乎在我的測試中起作用。
感謝您指出正確的方向。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.