查找扩展基类的Javascript应用程序中的所有类

obe*_*iro 7 javascript oop ecmascript-harmony ecmascript-6

我有这样的代码

class Animal{}
class Dog extends Animal {}
class Cat extends Animal {}
class Donkey extends Animal {}
Run Code Online (Sandbox Code Playgroud)

我想查看我的应用程序的Universe中的所有类,当我找到一个来自Animal的类时,我想创建一个该类型的新对象并将其添加到列表中.这允许我添加功能而无需更新事物列表.所以我可以避免以下情况:

var animals = [];
animals.push( new Dog() );
animals.push( new Cat() );
animals.push( new Donkey() );
Run Code Online (Sandbox Code Playgroud)

PS:我不想为我的类添加额外的功能或明确地调用它们.

Den*_*ler 8

那这个呢:

\n
class Animal {\n  static derived = new Set();\n}\nclass Dog extends Animal {\n  static dummy = Animal.derived.add(this.name);\n}\nclass Cat extends Animal {\n  static dummy = Animal.derived.add(this.name);\n}\nclass Donkey extends Animal {\n  static dummy = Animal.derived.add(this.name);\n}\n\nconsole.log(Animal.derived);\n
Run Code Online (Sandbox Code Playgroud)\n

我在 TypeScript 环境中尝试过这个。结果:

\n
Set(3)\xc2\xa0{"Dog", "Cat", "Donkey"}\n
Run Code Online (Sandbox Code Playgroud)\n

无需实例化类。

\n

  • 我建议使用“this”而不是“this.name”。根据范围,可以使用不同的 Cat 类。但是将“static”与“this”以及集合结合起来是一个很好的解决方案。-- 在 Animal 构造函数上,您可以轻松检查 `this.constructor` 是否在集合中,以确保每个扩展类将自身添加到集合中。 (3认同)
  • 老问题,但你可以完全跳过虚拟并简单地写:`static { Animal.driven.add(this.name); }` (您也可以根据需要拥有任意多个 `static{}`。它们将按顺序执行。) (3认同)

obe*_*iro 6

这是我到目前为止发现的 http://jsbin.com/xiroyurinu/1/edit?js,console,output

class Animal{}
class Dog extends Animal {}
class Cat extends Animal {}
class Donkey extends Animal {}

var animals = getAllSubclasses(Animal);

console.log(animals.map(function(c){ return new window[c] })) // creates objects
document.body.innerText = animals; // Dog, Cat, Donkey
Run Code Online (Sandbox Code Playgroud)

和魔法

function getAllSubclasses(baseClass) {
  var globalObject = Function('return this')(); 
  var allVars = Object.keys(globalObject);
  var classes = allVars.filter(function (key) {
  try {
    var obj = globalObject[key];
        return obj.prototype instanceof baseClass;
    } catch (e) {
        return false;
    }
  });
  return classes;
}
Run Code Online (Sandbox Code Playgroud)

这种方法的主要缺点是我无法使用 ES6 模块导入,并且必须执行老式且简单的文件连接,但这仍然比什么都不做要好。

PS:仍在等待更好的答案

UPD:是的,我知道要使用它,所有类都必须在全局范围内定义,这就是为什么我寻找更好的方法来做到这一点。

  • 在一般情况下,不能保证这些构造函数会附加到“window”,并且在几乎所有标准模块化 JS 代码中,它们都不会附加到“window”。 (4认同)

Ser*_*lov 6

我认为你可以使用装饰器。例如,您可以创建@Extends()一个并提供基类作为参数,例如@Extends(Animal). 在装饰器函数中,您可以获取用@Extends 装饰的类的名称,并将其放入数组或对象中。不知道它是否适用于浏览器,但应该适用。在带有 TypeScript 的 Node 中,我会执行以下操作:

import { MyClassMetadata } from './';

export function Extends(parent): (...args: any[]) => void {
    return (target: object): void => {
        MyClassMetadata.someVariableToStoreChildren[parent.constructor.name].push(
            target,
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以访问存储给定类的子项数组的 MyClassMetadata 变量,并以您想要的方式使用它。您可以使用它并获得所需的结果。

  • 可能是因为装饰器不是 js 标准的一部分(还没有?)。你需要打字稿或像 babel 这样的转译器 (2认同)