【问题标题】:How can I get all the ancestors' methods in JS (prototypal inheritance)?如何在 JS 中获取所有祖先的方法(原型继承)?
【发布时间】:2021-11-16 20:57:03
【问题描述】:

我需要在 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' && property !== 'constructor'
    );
}))

【问题讨论】:

  • 您期望该示例的确切输出是什么?你需要见方法的所有者吗?有什么具体的顺序吗?
  • 其次,您是否希望列出属于Object.prototype 的原型函数?
  • 嗨!在我写的代码中,输出的只是D的方法,不需要看方法的拥有者,顺序也无所谓。我不需要 Object 的方法。如果我将 dd.__proto__ 更改为 dd.prototype,我会得到 C 的方法;相反,如果我写 dd.prototype.__proto__,我得到 B 的方法;要获得 A 的方法,我必须放入 dd.prototype.__proto__.__proto__。这使得这项工作难以自动化。

标签: javascript inheritance methods prototype prototypal-inheritance


【解决方案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" && 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" && 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))));

【讨论】:

  • 非常感谢,伙计。这正是我一直在寻找的。我唯一修改的是第一个yield,以便只获取方法名称。
猜你喜欢
  • 2011-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-16
  • 1970-01-01
  • 1970-01-01
  • 2015-03-19
  • 1970-01-01
相关资源
最近更新 更多