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

时间:2017-05-31 14:58:48

标签: 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' });




6 个答案:

答案 0 :(得分:5)

您无法修改函数的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);




修改

我回来了!所以......正如我之前在评论中所说,我认为我已经确定了你的问题。我的回答有点太快,并没有看出你的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




答案 1 :(得分:3)

name是您要将其设置为的Function对象的保留属性。您无法设置它。

name属性的文档位于MDN

答案 2 :(得分:2)

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

您可以使用传播运算符对只读对象进行浅表复制以使其可读,但是根据您的情况,您可能不希望这样做。

let x = [...y];

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

let x = JSON.parse(JSON.stringify(y));

答案 3 :(得分:1)

如果您在 Angular + TypeScript 中出现此错误:

错误/无效:

@Output whatever_var = new EventEmitter();

好/正确:

@Output() whatever_var = new EventEmitter();

答案 4 :(得分:1)

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

obj = { ...obj, name: { first: 'hey', last: 'there'} }

答案 5 :(得分:0)

我在Angular中遇到了这个问题,同时从ActivatedRoute的queryParams中设置了一个局部变量,并试图有条件地覆盖或合并...事先复制就可以了:

updateQp(qp = {}, force = false) { 
    let qpLoc = Object.assign({}, this.queryParamsLocal)
    this.queryParamsLocal = force ? qp : Object.assign(qpLoc, qp)
}