#javascript #inheritance #methods #prototype #prototypal-inheritance
Вопрос:
Мне нужно создать функцию в JS, которая получает все методы из всего дерева наследования, чтобы вставить по одному <button>
для каждого метода. У меня есть этот код
function A () {
}
A.prototype.a = function () {
console.log('a');
}
function B () {
this.super = A;
this.super();
}
B.prototype = new A;
B.prototype.constructor = B;
B.prototype.b = function () {
console.log('b');
}
function C () {
this.super = B;
this.super();
}
C.prototype = new B;
C.prototype.constructor = C;
C.prototype.c = function () {
console.log('c');
}
function D () {
}
D.prototype = C;
D.prototype.constructor = D;
D.prototype.d = function () {
console.log('d');
}
const dd = new D();
Мне нужен какой-то способ найти методы всего дерева на случай, если я не знал, сколько предков у объекта. Например: Если объект C имел A и B в качестве своих предков, мне нужны методы из A, B и C; Если объект D был дочерним объектом A-B-C, мне нужны методы из них четырех (A, B, C и D). Я могу вручную отследить каждый метод, чтобы написать код, который делает это за меня, но мне нужно, чтобы он был динамичным.
Это то, что я использую:
console.log(Object.getOwnPropertyNames(dd.__proto__).filter(function (property) {
return (
typeof dd.__proto__[property] === 'function' amp;amp; property !== 'constructor'
);
}))
Комментарии:
1. Каков точный результат, который вы ожидаете для примера? Вам нужно встретиться с владельцем метода? Какой-нибудь конкретный заказ?
2. Во-вторых, ожидаете ли вы, что будут перечислены функции прототипа, которые принадлежат
Object.prototype
?3. Привет! В коде, который я написал, выводится только метод D. Мне не нужно видеть владельца метода, и порядок не имеет значения. Мне не нужны методы Объекта. Если я изменю dd.__proto__ на dd.prototype, я получу метод C; Если вместо этого я напишу dd.prototype.__proto__, я получу метод B; чтобы получить метод A, я должен поместить dd.prototype._________________________________. Это затрудняет автоматизацию работы.
Ответ №1:
В вашем установочном коде допущена ошибка:
Изменить:
D.prototype = C;
Для:
D.prototype = new C;
Затем, чтобы получить список методов (даже если они не перечислимы), выполните рекурсивный вызов. Вы даже можете сделать из него генератор.
Чтобы прояснить, откуда берутся методы, я добавил к ним префикс с именем объекта-прототипа (например A.prototype
). Вы увидите, что когда функции с одинаковым именем существуют на нескольких уровнях цепочки прототипов, они попадают в список:
function * iterMethods(o) {
if (!o || o === Object.prototype) return;
for (let name of Object.getOwnPropertyNames(o)) {
try {
if (name !== "constructor" amp;amp; typeof o[name] === "function") {
yield o.constructor.name ".prototype." name;
}
} catch {}
}
yield * iterMethods(Object.getPrototypeOf(o));
}
// Your code:
function A () {
}
A.prototype.a = function () {
console.log('a');
}
function B () {
this.super = A;
this.super();
}
B.prototype = new A;
B.prototype.constructor = B;
B.prototype.b = function () {
console.log('b');
}
function C () {
this.super = B;
this.super();
}
C.prototype = new B;
C.prototype.constructor = C;
C.prototype.c = function () {
console.log('c');
}
function D () {
}
D.prototype = new C;
D.prototype.constructor = D;
D.prototype.d = function () {
console.log('d');
}
const dd = new D();
// The call:
console.log(Array.from(iterMethods(Object.getPrototypeOf(dd))));
Эту иерархию прототипов легче настроить, когда вы используете class ... extends
синтаксис. Я бы также не стал определять super
, как это ключевое слово, которое изначально доступно. Вот как это будет выглядеть:
function * iterMethods(o) {
if (!o || o === Object.prototype) return;
for (let name of Object.getOwnPropertyNames(o)) {
try {
if (name !== "constructor" amp;amp; typeof o[name] === "function") {
yield o.constructor.name ".prototype." name;
}
} catch {}
}
yield * iterMethods(Object.getPrototypeOf(o));
}
// class syntax version:
class A {
a() {
console.log('a');
}
}
class B extends A {
b() {
console.log('b');
}
}
class C extends B {
c() {
console.log('c');
}
}
class D extends C {
d() {
console.log('d');
}
}
const dd = new D();
// The call:
console.log(Array.from(iterMethods(Object.getPrototypeOf(dd))));
Комментарии:
1. Большое спасибо, чувак. Это именно то, что я искал. Единственное, что я изменил, — это первое
yield
, чтобы получить только имя метода.