По какой причине конструкторы классов ES6 нельзя назвать обычными функциями?

1

Конструкторы классов ES6 нельзя назвать нормальными. Согласно ES6 TypeError должен быть поднят, когда это будет сделано. Раньше я думал, что классы являются просто синтаксическим сахаром для функции-конструктора + функции в прототипе, но это немного не так.

Мне интересно, в чем причина этого? Если я не пропустил что - то, что мешает вызов функции с обычаем this, что может быть желательным для некоторых моделей.

Теги:
ecmascript-6
prototypal-inheritance

3 ответа

0

в чем причина этого?

Это гарантия. Когда вы вызывали конструктор function ES5 без new, он делал очень нежелательные вещи, терпя неудачу. Выброс исключения помогает вам заметить ошибку.

Конечно, они могли бы выбрать синтаксис вызова, чтобы он работал так же, как и строительство, но принудительное использование new ключевого слова - это хорошая вещь, которая помогает нам легко распознавать экземпляры.

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

Да, это принципиально изменилось в ES6. this значение инициализируется суперкласса, что позволяет подкласс встроенных команд с внутренними пазами - см здесь для подробностей. Это конфликтует с передачей пользовательского этого аргумента, и для согласованности никогда нельзя допускать этого.

  • 0
    Кстати, несколько желаемых шаблонов все еще могут быть реализованы с помощью Reflect.construct . Что конкретно вы ищете?
0

Напомним, что ваши два основных момента:

  1. Конструкторы классов ES6 нельзя назвать нормальными.

  2. Это предотвращает вызов функции с помощью этого

Первое, что нужно отметить, - это то, что с точки зрения поведения класса в классе времени это точки не связаны функционально. Вы могли бы, например, разрешить Foo() без new но все же Foo.call({}) ведут себя так, как будто это было new. Способность вызывать как функция позволяет установить this, но он не должен, так же Foo.bind({})() будет свяжите this, а затем вызвать функцию, но неизбежно this будет игнорироваться.

Для обоснования решения я не могу дать вам основной источник, но я могу сказать вам, что есть одна веская причина. Синтаксис класса ES6 - это "синтаксический сахар", но не для упрощенного кода, который, вероятно, у вас в голове. Возьмите, к примеру, этот фрагмент, учитывая вашу цель.

class Parent {}

class Child extends Parent {
  constructor() {
    // What is "this" here?
    super();
  }
}

Child.call({});

Что делать? В ES6 super() - это то, что на самом деле устанавливает this. Если вы попытаетесь получить доступ к this прежде чем вызвать super(), он выдает исключение. Ваш пример кода может работать с Base.call({}), так как он не имеет родительского конструктора, так this инициализируется фронт, но как только вы вызываете класс ребенка, this не имеет даже значения фронт. Если вы используете .call нет места, где можно поставить это значение.

Итак, следующий вопрос: почему дочерние классы не получают this до super()? Это связано с тем, что он позволяет синтаксису класса ES6 расширять встроенные типы, такие как Array Error и Map и любой другой встроенный тип конструктора. В стандартном ES5 это было невозможно, хотя с нестандартным __proto__ в ES5 его можно было моделировать грубо. Даже с __proto__ обычно является проблемой производительности для расширения встроенных типов. Включив это поведение в классы ES6, JS-двигатели могут оптимизировать код, так что расширение встроенных типов работает без повышения производительности.

Поэтому для ваших вопросов, да, они могут допускать Foo.call() или Foo(), но это должно было бы игнорировать this любом случае, чтобы разрешить расширение встроенных типов.

0

Пересмотр спецификации ES6 показывает, как вызов объекта функции класса без нового отключается путем объединения разделов 9.2.9 и 9.2.1:

9.2.9 MakClassConstructor (F)
...
3. Установите внутренний разъем Fs [[FunctionKind]] в "classConstructor".

и при указании метода [[call]] в отличие от метода [[contruct]] для функции:

(9.2.1) 2. Если внутренний слот Fs [[FunctionKind]] "classConstructor", введите исключение TypeError.

Никаких ограничений на функцию вызова в разделе "11.2.3" вызовы функций "ES5.1.

Таким образом, вы ничего не пропустили: вы не можете использовать apply в функции конструктора классов.

Основное обоснование, вероятно, как для того, чтобы сделать расширения класса довольно строгим упражнением, так и для обнаружения некоторых ранних форм ошибок. Например, вы не можете назвать Promise, кроме как конструктор - и выход из new, прежде чем вызов Promise ошибка программирования. Что касается проходящих классов, обратите внимание, что constructor свойство экземпляров класса установлено правильно (последний класс после того, как, возможно, несколько расширений) и .prototype свойства конструктора класса только для чтения - вы не можете динамически изменять прототип объекта, используемый для построить экземпляры класса, даже если вы можете изменить свойство prototype функции-конструктора.

Раньше я думал, что занятия были синтаксическим сахаром, но отошли от концепции.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню