是否有较简单的方法来检索原型链中某处的getter和setter方法?

时间:2019-03-18 08:13:08

标签: javascript getter-setter prototypal-inheritance

我有一个对象的引用,该对象在其原型链中某处具有某种属性的吸气剂和吸气剂。我想获得对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

但是这会调用功能而不能够与它们(或它们所在的原型对象)进行交互。

在上面的代码段中,有没有更清晰,更短的方法来实现我的目的?

1 个答案:

答案 0 :(得分:1)

  

这似乎很麻烦,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);
}