Есть ли менее громоздкий метод получения методов получения и установки, которые находятся где-то в цепочке прототипов? - PullRequest
2 голосов
/ 18 марта 2019

У меня есть ссылка на объект, который имеет геттер и сеттер для определенного свойства где-то в своей цепочке прототипов.Я хочу получить ссылку на методы получения и установки и объект, на котором они находятся.Я знаю, что могу сделать это, вручную перебирая каждый объект-прототип и проверяя 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 Ответ

1 голос
/ 18 марта 2019

Это кажется довольно громоздким, и 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);
}
...