Deep Analysis of 'Cannot assign to read only property 'name' of object' Error in JavaScript and Inheritance Mechanism Correction

Dec 03, 2025 · Programming · 29 views · 7.8

Keywords: JavaScript | Inheritance Mechanism | Read-Only Property

Abstract: This article delves into the root cause of the 'Cannot assign to read only property 'name' of object' error in JavaScript, analyzing the property descriptor of function objects' 'name' and ES5 inheritance mechanisms to reveal issues with 'this' context due to incorrect prototype chain setup. It explains how to properly use <code>Object.create()</code> and <code>Object.defineProperty()</code> to fix inheritance chains, providing complete code examples and best practices to help developers avoid common pitfalls.

Error Phenomenon and Initial Analysis

In JavaScript development, the error "Cannot assign to read only property 'name' of object" often occurs when attempting to modify a read-only property. The following code example illustrates a typical scenario:

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

The error only occurs when trying to set the <code>name</code> property, while other properties like <code>type</code> work normally. This suggests that the <code>name</code> property has special descriptor configurations.

Property Descriptor of Function Objects' 'name'

In JavaScript, function objects have a built-in <code>name</code> property that stores the function name. Its property descriptor can be inspected using <code>Object.getOwnPropertyDescriptor()</code>:

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

console.log(Object.getOwnPropertyDescriptor(BaseClass, 'name'));
// Output: { value: 'BaseClass', writable: false, enumerable: false, configurable: true }

The descriptor shows <code>writable: false</code>, meaning the <code>name</code> property is read-only and cannot be directly assigned. However, since <code>configurable: true</code>, the property can be redefined using <code>Object.defineProperty()</code>:

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

console.log(BaseClass.name); // Output: Foo

While this approach works, it is not a fundamental solution as it overlooks deeper issues in the inheritance mechanism.

Errors and Corrections in ES5 Inheritance Mechanism

The core issue lies in incorrect setup of the inheritance chain. In the original code:

ExtendedClass.prototype = Object.create(BaseClass);

This line sets <code>ExtendedClass.prototype</code> to an instance of the <code>BaseClass</code> constructor function, rather than <code>BaseClass.prototype</code>. This causes the <code>this</code> context in <code>BaseClass.apply(this, arguments)</code> to point to the function object <code>BaseClass</code> itself, not its instance:

function BaseClass(data) {
  console.log(this instanceof BaseClass); // false
  console.log(this instanceof Function); // true
  console.log(this.name); // 'BaseClass'
  
  Object.assign(this, data); // Attempts to modify the read-only 'name' property of the function object
}

Thus, when passing <code>{ name: 'foo' }</code>, <code>Object.assign()</code> tries to modify the <code>name</code> property of the <code>BaseClass</code> function, triggering the read-only error.

Correct Inheritance Implementation

The standard approach for implementing ES5-style inheritance in JavaScript involves two key steps:

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

The first line sets <code>ExtendedClass.prototype</code> to a new object based on <code>BaseClass.prototype</code>, establishing the correct prototype chain. The second line fixes the <code>constructor</code> property to ensure instances correctly identify their constructor.

A complete corrected code example is as follows:

function BaseClass(data) {
  console.log(this instanceof BaseClass); // true
  console.log(this instanceof Function); // false
  console.log(this.name); // undefined (initial state)
  
  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 (function name remains unchanged)
console.log(ExtendedClass.name); // ExtendedClass

Now, <code>this</code> in <code>BaseClass</code> points to an instance of <code>ExtendedClass</code>, not the function object itself. <code>Object.assign()</code> operates on writable properties of the instance, allowing <code>name</code> to be set normally.

Supplementary Solutions and Best Practices

Beyond fixing inheritance chains, read-only property issues may arise in other contexts. For example, in Angular+TypeScript+NgRX environments, selectors might return read-only objects:

let x = [...y]; // Shallow copy of read-only object
let x = JSON.parse(JSON.stringify(y)); // Deep copy to remove store references

However, these methods should be used cautiously as they may impact performance or data consistency. Best practices include:

  1. Always use <code>Object.create(BaseClass.prototype)</code> instead of <code>Object.create(BaseClass)</code> for setting prototype chains.
  2. Check descriptors with <code>Object.getOwnPropertyDescriptor()</code> before modifying properties.
  3. For read-only but configurable properties, consider redesigning code logic rather than forcing modifications.
  4. In frameworks like Redux/NgRX, follow immutable data patterns to avoid direct state object modifications.

By understanding JavaScript property descriptors and inheritance mechanisms, developers can more effectively debug and prevent such errors, writing more robust and maintainable code.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.