Невозможно назначить только для чтения свойство 'name' объекта ' [object Object]'


Следующий код выдаст ошибку только для свойства name. Это можно было бы исправить, указав свойство name как доступное для записи в аргументах Object.create, но я пытаюсь понять, почему это происходит(и, возможно, есть более элегантный способ исправить это).

var BaseClass = function (data) {
  Object.assign(this, data);
}

var ExtendedClass = function () {
  BaseClass.apply(this, arguments);
}

ExtendedClass.prototype = Object.create(BaseClass);

console.log(new ExtendedClass({ type: 'foo' }));
new ExtendedClass({ name: 'foo' });
3   5   2017-05-31 17:58:47

3 ответа:

Вы не можете изменить свойство name функции. Дескриптор говорит, что это не writable...

var BaseClass = function (data) {
  Object.assign(this, data);
};

console.log(Object.getOwnPropertyDescriptor(BaseClass, 'name'));
Но поскольку это configurable, Вы можете использовать Object.defineProperty().

var BaseClass = function (data) {
  Object.assign(this, data);
};

Object.defineProperty(BaseClass, 'name', {
  writable: true,
  value: 'Foo'
});

console.log(BaseClass.name);

EDIT

Я вернулся! Так... Как я уже говорил ранее в комментариях, я думаю, что определил вашу проблему. Я ответил немного слишком быстро и не увидел, что ваше наследство ES5 неправильно.

ExtendedClass.prototype = Object.create(BaseClass); это не то, что вы хотите сделать. Это означает, что прототипом ExtendedClass становится функция-конструктор. Это, очевидно, порождает неожиданное поведение.

function BaseClass(data) {
  console.log(this instanceof BaseClass); // "this" is not an instance of "BaseClass"
  console.log(this instanceof Function); // "this" is a function
  console.log(this.name); // "this" is "BaseClass"
  
  Object.assign(this, data);
}

function ExtendedClass() {
  BaseClass.apply(this, arguments);
}
ExtendedClass.prototype = Object.create(BaseClass);

new ExtendedClass({ type: 'foo' });

В вашем коде this является функцией и ссылается на BaseClass. Именно поэтому вам не разрешается изменять его название...

На самом деле, при работе с наследованием в JavaScript, как правило, нужны следующие две строки:

ExtendedClass.prototype = Object.create(BaseClass.prototype);
ExtendedClass.prototype.constructor = ExtendedClass;

Вот допустимая реализация:

function BaseClass(data) {
  console.log(this instanceof BaseClass); // "this" is an instance of "BaseClass"
  console.log(this instanceof Function); // "this" is not a function
  console.log(this.name); // "this" has no name yet
  
  Object.assign(this, data);
}

function ExtendedClass() {
  BaseClass.apply(this, arguments);
}
ExtendedClass.prototype = Object.create(BaseClass.prototype);
ExtendedClass.prototype.constructor = ExtendedClass;

var instance = new ExtendedClass({ name: 'foo' });

console.log(instance.name); // foo
console.log(BaseClass.name); // BaseClass
console.log(ExtendedClass.name); // ExtendedClass

Свойство name зарезервировано для Объекта Function, в который вы пытаетесь его установить. Вы не можете установить его.

Документация для свойства name находится по адресу MDN.

Если вы получите эту ошибку в Angular+TypeScript:

НЕВЕРНО / НЕВЕРНО:

@Output whatever_var = new EventEmitter ();

ХОРОШО / ПРАВИЛЬНО:

@Output () whatever_var = new EventEmitter ();