如何在 Javascript 中实现此 C++ 模式?

How to implement this C++ pattern in Javascript?

来自继承 class 的方法应该 return 继承自谁的对象类型。在 C++ 中,这种行为很容易实现。但是我不知道如何在 javascript 中做到这一点。我知道错了,但我是这样写的。

class A {
 someMethod() {
  return new A();
 }
}
class B extends A {
}
var b = new B();
b.someMethod() // should return an object of type B not A

在 C++ 中这很容易做到

template <typename c>
struct a
{
    a() : _value(NULL) {}
    a(std::string v) : _v(v) {}
    static c* from_string(std::string &v)
    {
        return new c(v);
    }
private:
    std::string _v;
};

struct b : public a<b>
{
    b() : b<a>() {}
    b(std::string &v) : node<b>(a) {}
};

如何使用 javascript 来实现?

编辑

这不是继承class的方式,而是一种继承和创建对象的特殊模式。 Node.Js 中有几个例子,例如 Buffer.from、Buffer.alloc。但我想从基础 class.

重现这个

有人告诉我可以使用以下脚本解决我的问题:

class A {
 method() { return this.constructor(); }
}

class B {}

var b = new B();
var b1 = b.method();

我真正想做的是下面这样的事情。

class A {
 static from() { return new this.constructor() }
};
class B extends A {};

a = A.from();
b = B.from();

a instanceof A // should be true
b instanceof B // should be true.


编辑 2

我发现了一些东西。

我在 typescript 中发现相同的 C++ 行为可以归档如下:

class a {

    static from<t extends a>(c: { new(): t }) : t {
        return new c();
    }

};

class b extends a {
}

let b1 = a.from(b);

b1 instanceof b
b1 instanceof a

console.log(b1);

es6 等价物是:

class a {
    static from(c) {
        return new c();
    }
}
;
class b extends a {
}
let b1 = a.from(b);
b1 instanceof b;
b1 instanceof a;
console.log(b1);
//# sourceMappingURL=index.js.map

正如我所说:C++ 中的模板 class 实际上是一个元 class。它用于从中构建其他 classes。

因此我们可以将此观察应用于 JavaScript。我玩过,这是我能得到的最接近的东西。先定义一个"template":

function TemplateA(cls) {
    class A {
        static from() {
            return new cls();
        };
        foo() {
            return -1;
        };
    };
    return A;
};

现在定义自定义 "extends":

function Extends(base, derived) {
    // Update statics
    // (these should not be overwritten)
    var common = {name: 1, prototype: 1, length: 1};
    var statics = Object.getOwnPropertyNames(base)
        .filter(el => !common[el]);
    statics.forEach(el => {
        derived[el] = base[el];
    });
    // Update instance methods
    var instanceMethods = Object.getOwnPropertyNames(base.prototype);
    instanceMethods.forEach(el => {
        derived.prototype[el] = base.prototype[el];
    });
};

最后用法:

class B {
    test() { return 1; }
};

> Extends(TemplateA(B), B);
> var b = B.from();
> b instanceof B;
true
> var x = new B();
> x.foo();
-1
> x.test();
1

看来如你所愿。但这有一些缺点。它不是真正的继承(原型只是更新)。特别是 B 不是 A<B> 的子 class(实际上 Extends 之后甚至不存在这样的 class)。另一方面,JavaScript 的 inheritance/prototyping 非常独特,与 C++ 截然不同,因此我们不能指望一切正常。

旁注:

  • 安全吗?大概。然而,它确实需要开发人员的大量纪律。例如,覆盖您不想覆盖的内容太容易了。
  • 我会在生产环境中使用它吗?不太可能。无论您试图完成什么,很可能都可以通过其他一些标准方式实现。将解决方案视为一种学术乐趣。
  • 最后:谁告诉你C++方式是最好的方式?你的游泳技术在攀岩时并没有多大用处,对吧?所以我强烈建议你重新考虑你的整个架构并尝试以不同的方式做事。