Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot assign to read only property 'name' of object '[object Object]'

Tags:

javascript

oop

The following code will throw an error only for the name property. It could be fixed by specifying name property as writable in Object.create arguments but I'm trying to understand why is this happening(and maybe there is a more elegant way to fix it).

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' });
like image 320
G07cha Avatar asked May 31 '17 14:05

G07cha


People also ask

Can not assign property to read only?

The error "Cannot assign to read only property of object" occurs when we try to change a property of an object that has been frozen or when a property has been defined with Object. defineProperties() . To solve the error, create a copy of the object or array, or set the property to writable .

Why is object read only JavaScript?

The JavaScript strict mode-only exception "is read-only" occurs when a global variable or object property that was assigned to is a read-only property.

How do you assign values to readonly property in typescript?

Sample Code: class C { readonly readOnlyProperty: string; constructor(raw: string) { this. process(raw); } process(raw: string) { this. readOnlyProperty = raw; // [ts] Cannot assign to 'readOnlyProperty' because it is a constant or a read-only property. } }

What is read only property in JavaScript?

The readOnly property sets or returns whether a text field is read-only, or not. A read-only field cannot be modified. However, a user can tab to it, highlight it, and copy the text from it. Tip: To prevent the user from interacting with the field, use the disabled property instead.


2 Answers

If you get this error in Angular+Typescript+NgRX:

You can use the spread operator to take a shallow copy of a readonly object to make it readable, however you may not want this depending on your situation.

let x = [...y];

If you're using Redux / NgRX, there's a chance your selector could be returning a readonly object with a reference to the store, which can throw exceptions when trying to alter that object property via template binding. Depending on your situation, you can take a deep copy to remove the store reference.

let x = JSON.parse(JSON.stringify(y));
like image 120
user12180028 Avatar answered Oct 10 '22 15:10

user12180028


You cannot modify the name property of a function. The descriptor says it is not writable...

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

console.log(Object.getOwnPropertyDescriptor(BaseClass, 'name'));

But since it is configurable, you could use Object.defineProperty().

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

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

console.log(BaseClass.name);

EDIT

I'm back! So... As I said previously in comments, I think I have identified your problem. I answered a bit too fast and did not see that your ES5 inheritance is wrong.

ExtendedClass.prototype = Object.create(BaseClass); is not what you want to do. Doing so means the prototype of ExtendedClass becomes a constructor function. This obviously generates an unexpected behavior.

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

In your code, this is a function and refers to BaseClass. That is why you are not allowed to modify its name...

In fact, when working with inheritance in JavaScript, you generally need these two lines:

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

Here is a valid implementation:

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
like image 21
Badacadabra Avatar answered Oct 10 '22 16:10

Badacadabra