通过原型继承扩展ES2015 [英] Extending ES2015 through prototype inheritance

查看:67
本文介绍了通过原型继承扩展ES2015的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建一个库,在这里我想提供一个帮助程序来扩展基类,以便用户即使不自己使用ES2015也可以扩展基类。问题是,如果基类恰好在ES2015中(因为它不是通过transpiler发送的),那么我从子类对父构造函数的调用将失败,并显示以下内容:

I am making a library where I would like to provide a helper to extend the base class so that users can extend it even if they are not using ES2015 themselves. The issue is that if the base class happens to be in ES2015 (because it isn't sent through transpiler), my calling of parent constructor from subclass fails with:


类构造函数Foo必须在没有'new'的情况下调用。

Class constructor Foo cannot be invoked without 'new'

我要实现的示例:

class Foo {
  constructor() {
    console.log("In Foo");
  }

  superMethod() {
    return console.log("In super method");
  }

  static classMethod() {
    return console.log("In class method");
  }
}

Foo.extendClass = function (constructor, methods) {
  const currentClass = this;
  if (typeof constructor !== 'function') {
    methods = constructor;
    constructor = function () {
      return Object.getPrototypeOf(constructor).apply(this, arguments);
    };
  }
  constructor.prototype = Object.create(currentClass.prototype, {
    constructor: {
      value: constructor,
      writable: true,
      configurable: true
    }
  });
  Object.setPrototypeOf(constructor, currentClass);
  Object.assign(constructor.prototype, methods);
  return constructor;
};

const Bar = Foo.extendClass({
  subMethod: function() {
    return console.log("In sub method");
  }
});

b = new Bar();

问题出在这一行:

return Object.getPrototypeOf(constructor).apply(this, arguments);

那么我该如何调用父级的构造函数?我以为ES2015只是标准原型继承的基础,但看起来您无法模拟它?还有另一种在运行时定义子类的方法吗?

So how can I call into parent's constructor? I thought ES2015 are just a sugar on top of standard prototype inheritance, but it looks like you cannot simulate it? Is there another way to define subclasses at run time?

推荐答案

ES6在之间创建了更清晰的区别[[调用]] [[Construct]] 操作。 ES6类只能使用 [[Construct]] 操作来构造,但是 .call / .apply [[Call]] 操作。要使用 [[Construct]] ,您需要使用 Reflect.construct()创建新实例。例如,

ES6 created a clearer distinction between [[Call]] and [[Construct]] operations. ES6 classes can only be constructed using a [[Construct]] operation, but .call/.apply are [[Call]] operations. To use [[Construct]], you'll need to use Reflect.construct() to create the new instance. e.g.

constructor = function () {
  return Reflect.construct(Object.getPrototypeOf(constructor), arguments);
};

constructor = function () {
  return Reflect.construct(currentClass, arguments);
};

不过我还要注意,这也忽略了ES6中的另一个新功能,即 new.target 。您还希望通过执行

I'll also note however that this also ignores another feature new in ES6, which is new.target. You'll also want to preserve that, by doing

constructor = function () {
  return Reflect.construct(currentClass, arguments, new.target);
};

确保事物的行为与类语法相同。

to ensure that the things behave the same way as class syntax would.

还请注意,您必须不要在此函数内使用 this 。新实例是 Reflect.construct 的返回值,因此,如果您想在自己的自定义构造函数中使用它,则需要这样做

Also note that you must not use this inside this function. It is the return value of Reflect.construct that is the new instance, so if you wanted to work with it in your own custom constructor, you'll want to do

constructor = function () {
  const _this = Reflect.construct(currentClass, arguments, new.target);

  _this.foo = "foo";
  return _this;
};

但是,如果您考虑一下,这基本上和做

however, if you think about it, this is essentially all the same as doing

constructor = class extends currentClass {}

这篇关于通过原型继承扩展ES2015的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆