无法分配给对象'[object Object]'的只读属性'name'

Kon*_*zov 9 javascript oop

以下代码仅针对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' });
Run Code Online (Sandbox Code Playgroud)

小智 23

如果您在Angular+Typescript+NgRX 中遇到此错误:

您可以使用扩展运算符获取只读对象的浅拷贝以使其可读,但是根据您的情况,您可能不希望这样做。

let x = [...y];
Run Code Online (Sandbox Code Playgroud)

如果您使用的是 Redux / NgRX,则您的选择器可能会返回一个带有对存储的引用的只读对象,这在尝试通过模板绑定更改该对象属性时可能会引发异常。根据您的情况,您可以进行深层复制以删除商店引用。

let x = JSON.parse(JSON.stringify(y));
Run Code Online (Sandbox Code Playgroud)

  • 我在 Angular+ngrx 错误中收到此错误,但我不明白为什么我为每个对象都会得到它,即使对于不在状态或减速器中的对象也是如此。 (2认同)

Bad*_*bra 6

您无法修改name函数的属性.描述符说它不是writable......

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

console.log(Object.getOwnPropertyDescriptor(BaseClass, 'name'));
Run Code Online (Sandbox Code Playgroud)

但既然如此configurable,你可以使用Object.defineProperty().

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

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

console.log(BaseClass.name);
Run Code Online (Sandbox Code Playgroud)


编辑

我回来了!所以......正如我之前在评论中所说,我认为我已经确定了你的问题.我的回答有点太快,并没有看到你的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' });
Run Code Online (Sandbox Code Playgroud)

在您的代码中,this是一个函数并引用BaseClass.这就是为什么不允许你修改它的名字......

实际上,在JavaScript中使用继承时,通常需要以下两行:

ExtendedClass.prototype = Object.create(BaseClass.prototype);
ExtendedClass.prototype.constructor = ExtendedClass;
Run Code Online (Sandbox Code Playgroud)

这是一个有效的实现:

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
Run Code Online (Sandbox Code Playgroud)

  • 哇!非常感谢您的投票,伙计。我很感激。事实上,Stack Overflow 并不总是公平的......你通常会因为快速和简短的答案而获得更多的声誉,但是当问题很有趣时,我通常更喜欢慢慢来并发布长的答案。老实说,就声誉点而言,这不是一项有利可图的业务。我发布了一些深入的答案,但什么也没收到。但至少,如果它可以在未来帮助某人,那就太好了。快乐 JavaScript!:) (2认同)

Man*_*nas 6

使用 ES7+ 或 TypeScript 扩展运算符功能来克服这个问题

obj = { ...obj, name: { first: 'hey', last: 'there'} }
Run Code Online (Sandbox Code Playgroud)


Mis*_*saz 5

这是您尝试将其设置到的对象name的保留属性。您无法设置它。Function

name 属性的文档位于MDN