我有一个对象的引用,它在原型链的某个地方有一个getter和setter用于某个属性。我想获得对getter和setter方法的引用,以及它们所在的对象。我知道我可以通过手动迭代每个原型对象并检查hasOwnProperty
来完成它,如下面的代码片段所示:
const obj2 = (() => {
const baseProto = {
get prop() {
return 'propval';
},
set prop(newVal) {
console.log('setting...');
}
};
const obj1 = Object.create(baseProto);
return Object.create(obj1);
})();
// From having a reference to obj2, want to get the getter or setter methods,
// and want to get the object they're on, without invoking them:
let currentObj = obj2;
const propToFind = 'prop';
let get, set, foundProto;
while (currentObj) {
if (currentObj.hasOwnProperty(propToFind)) {
foundProto = currentObj;
({ get, set } = Object.getOwnPropertyDescriptor(currentObj, propToFind));
break;
}
currentObj = Object.getPrototypeOf(currentObj);
}
if (foundProto) {
console.log('Found:', get, set, foundProto);
}
这看起来相当麻烦,而且while
循环很难看。当然,可以使用非常简单的代码调用getter和setter,使用当前对象的调用上下文
obj2.prop = 'newVal'; // invoke setter
const val = obj2.prop; // invoke getter
但是这会调用函数而不能与它们(或它们所在的原型对象)进行交互。
在上面的片段中,是否有更清晰,更短的方式来实现我正在做的事情?
这看起来相当麻烦,而且
while
循环很难看
我不认为这很麻烦,这正是你在原型链上任何地方寻找物业时必须要做的事情。
当然,您不必编写while
循环,迭代可以很容易地表示为for
循环:
let get, set, foundProto;
for (let currentObj = obj2; currentObj; currentObj = Object.getPrototypeOf(currentObj)) {
if (currentObj.hasOwnProperty('prop')) {
foundProto = currentObj;
({ get, set } = Object.getOwnPropertyDescriptor(currentObj, 'prop'));
break;
}
}
if (foundProto) {
console.log('Found:', get, set, foundProto);
}
你当然也可以写一个辅助函数来做这个,比如
function getInheritedPropertyDescriptor(obj, prop) {
for (; obj != null; obj = Object.getPrototypeOf(obj)) {
if (Object.prototype.hasOwnProperty.call(obj, prop)) {
return { foundProto: obj, ...Object.getOwnPropertyDescriptor(obj, prop) };
}
}
return null;
}
var result = getInheritedPropertyDescriptor(obj2, 'prop');
if (result) {
console.log('Found:', result.get, result.set, result.foundProto);
}