Расширение ES2015 за счет наследования прототипов - PullRequest
0 голосов
/ 22 сентября 2019

Я создаю библиотеку, в которой я хотел бы предоставить помощника для расширения базового класса, чтобы пользователи могли расширять его, даже если они сами не используют ES2015.Проблема заключается в том, что если базовый класс находится в ES2015 (потому что он не передается через транспортер), мой вызов родительского конструктора из подкласса завершается неудачно с помощью:

Конструктор класса Foo не может быть вызван без'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 - просто сахар на вершине стандартного наследования прототипа, но похоже, что вы не можете его смоделировать?Есть ли другой способ определить подклассы во время выполнения?

1 Ответ

1 голос
/ 23 сентября 2019

ES6 дал более четкое различие между операциями [[Call]] и [[Construct]].Классы ES6 могут быть созданы только с использованием операции [[Construct]], но .call / .apply являются операциями [[Call]].Чтобы использовать [[Construct]], вам нужно будет использовать Reflect.construct() для создания нового экземпляра.например,

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

или

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

Я также отмечу, что это также игнорирует еще одну новую функцию в ES6, которая является new.target.Вы также захотите сохранить это, выполнив

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

, чтобы гарантировать, что все будет вести себя так же, как синтаксис класса.

Также обратите внимание, что must не использовать this внутри этой функции.Это возвращаемое значение Reflect.construct, которое является новым экземпляром, поэтому, если вы хотите поработать с ним в своем собственном конструкторе, вы, однако, захотите сделать

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

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

, если подумаете оэто, по сути, все то же самое, что и

constructor = class extends currentClass {}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...