Классы ES2015 мешают установке прототипа - PullRequest
0 голосов
/ 26 мая 2018

Я обнаружил, что классы ES2015 препятствуют установке (переопределению) своего прототипа.

Часто утверждается, что классы ES2015 являются просто "синтаксическим сахаром" поверх функций конструктора ES5 и наследования на основе прототипов.
Ноэто разница в поведении ...

Является ли это поведение частью спецификации ES2015?Я не нашел никакой документации по этому поводу ...

Следующие примеры иллюстрируют разницу:

function Pet() {}
Pet.prototype.eat = () => {
  console.log('Pet is eating ...');
}

Pet.prototype = {eat: function(){console.log('Pet is REALLY eating ...')}};

const pet = new Pet();
pet.eat();     // -> Pet is REALLY eating ...

console.log(Object.getOwnPropertyDescriptor(Pet, 'prototype'));

=> Переопределение прототипа работ для животных

class Pet {
  eat() {
    console.log('Pet is eating ...');
  }
}


Pet.prototype = {eat: function(){console.log('Pet is REALLY eating ...')}};

const pet = new Pet();
pet.eat();     // -> Pet is eating ...

console.log(Object.getOwnPropertyDescriptor(Pet, 'prototype'));

=> Переопределение прототипа Pet не работает

Любые указатели на документацию этого поведения приветствуются ...

1 Ответ

0 голосов
/ 26 мая 2018

Разница в том, что при создании с class объект prototype устанавливается на writable: false, поэтому вы не можете заменить Pet.prototype присвоением.Вы можете увидеть эту разницу в вашем Object.getOwnPropertyDescriptor() вызове при удалении строгого режима.

Первый пример кода OP показывает это:

{
  ...
  "writable": true,
  "enumerable": false,
  "configurable": false
}

Второй пример кода OP показывает это:

{
  ...
  "writable": false,
  "enumerable": false,
  "configurable": false
}

Свойство writable определяет, может ли свойство Pet.prototype быть присвоено новое значение или нет (например, заменено новым объектом).Значение false означает, что вы не можете заменить Pet.prototype, используя присвоение.Поэтому, когда ваш код пытается это сделать, он терпит неудачу.

Вы по-прежнему можете добавлять или удалять отдельные свойства объекта-прототипа, просто не заменяя весь объект.Это имеет некоторый смысл для меня, потому что замена всего объекта-прототипа отменяет все определение class.Возможно, вы могли бы изменить объект Pet.prototype для записи, если бы у вас была реальная причина заменить его.

Это описано в спецификации ES 2015.В 14.5.14 Семантика времени выполнения: ClassDefinitionEvaluation , на шаге 16 она делает это:

Perform MakeConstructor (F, false, proto).

Этот аргумент false делает созданный прототип недоступным для записи (поэтому его нельзя заменить).

И, если вы посмотрите на 9.2.8 MakeConstructor () , вы увидите это на шаге 6:

Пусть status будет DefinePropertyOrThrow (F, "prototype ", PropertyDescriptor {[[Value]]: prototype, [[Writable]]: writablePrototype, [[Enumerable]]: false, [[Configurable]]: false}).

ГдеАтрибут writable получает значение false, которое ему ранее было передано.


Часто утверждается, что классы ES2015 являются просто "синтаксическим сахаром" поверх функций конструктора ES5.и наследование на основе прототипа.Но это различие в поведении ...

Хотя общая работа методов, определенных в class, почти одинакова, этот другой ответ описывает несколько других различий между использованием classпо сравнению с ручным назначением прототипа: В javascript, чем отличаются класс и конструктор?

...