无法分配给 JavaScript 中对象的只读属性

无法分配给 JavaScript 中对象的只读属性

Cannot assign to read only property of Object in JavaScript

当我们尝试更改已冻结的对象的属性或使用定义的属性时,会出现错误“无法分配给对象的只读属性” Object.defineProperties()

要解决该错误,请创建对象或数组的副本,或将属性设置为writable

无法分配给只读属性错误

以下是错误发生方式的 3 个示例。

索引.js
// 👇️ With OBJECTS 👇️ const obj = { name: 'James', }; Object.freeze(obj); // ⛔️ Error: Cannot assign to read only property 'name' of object '#<Object>' obj.name = 'Alice'; // ------------------------------------------------------ // 👇️ With ARRAYS 👇️ const arr = ['a', 'b', 'c']; Object.freeze(arr); // ⛔️ Error: Cannot assign to read only property '0' of object '[object Array]' arr[0] = 'z'; // ------------------------------------------------------ // 👇️ With Object.defineProperties() 👇️ const obj2 = {}; Object.defineProperties(obj2, { country: { value: 'Germany', // 👉️ must be set writable: true // writable: true, // 👈️ uncomment this }, }); // ⛔️ Error: Cannot assign to read only property 'country' of object '#<Object>' obj2.country = 'Austria';

前两个错误的发生是因为对象或数组已被
Object.freeze()
方法冻结。

常见错误原因

最常见的错误原因是:

  1. 试图将属性分配给冻结的对象或数组。
  2. 使用时忘记设置writabletrueObject.defineProperties
  3. 在使用第三方库(例如 React.js)时尝试就地修改状态对象或数组。

创建数组或对象的副本

无法再更改冻结的对象,但您可以创建数组或对象的副本并更改副本。

索引.js
// ✅ With OBJECTS const obj = { name: 'James', }; Object.freeze(obj); const objCopy = {...obj}; // 👈️ create copy objCopy.name = 'Alice'; console.log(objCopy); // 👉️ {name: 'Alice'} // -------------------------------------- // ✅ With ARRAYS const arr = ['a', 'b', 'c']; Object.freeze(arr); const arrCopy = [...arr]; // 👈️ create copy arrCopy[0] = 'z'; console.log(arrCopy); // 👉️ ['z', 'b', 'c']

我们使用
扩展语法 (…)创建对象和数组的副本,因此我们可以更改它们。

尝试对只读数组进行排序

当您尝试对只读数组进行排序时也会发生此错误,因为该
Array.sort()方法会在适当的位置对数组进行排序。

索引.js
const arr = ['a', 'b', 'c']; Object.freeze(arr); // ⛔️ TypeError: Cannot assign to read only property '0' of object '[object Array]' arr.sort();

要解决该错误,
请创建数组的副本并对副本进行排序

索引.js
const arr = ['a', 'b', 'c']; Object.freeze(arr); // 👇️ create copy const arrCopy = [...arr]; // 👇️ sort the copy arrCopy.sort(); console.log(arrCopy); // 👉️ [ 'a', 'b', 'c' ]

我们使用扩展语法 (…) 创建数组的副本并调用
sort()副本上的方法。

现在我们不再试图改变只读数组。

您还可以使用该Array.slice()方法创建冻结数组的浅表副本。

索引.js
const arr = ['a', 'b', 'c']; Object.freeze(arr); // 👇️ create a shallow copy of the array const arrCopy = arr.slice(); arrCopy.sort(); console.log(arrCopy); // 👉️ [ 'a', 'b', 'c' ]

slice()不带任何参数调用该方法时,它返回原始数组的浅表副本。

设置writabletrue如果使用Object.defineProperties()

如果您在使用Object.defineProperties方法时遇到错误

,请将属性设置为
writableif 您想要更改其值。

索引.js
const obj2 = {}; Object.defineProperties(obj2, { country: { value: 'Germany', writable: true, // 👈️ set property to writable }, }); obj2.country = 'Austria'; console.log(obj2.country); // 👉️ "Austria"

country属性设置为writable,因此可以更改。

使用该方法时参数writable默认为falseObject.defineProperties()

如果您希望能够更改属性的值,请显式设置
writabletrue.

您可能必须在对象上设置的其他属性是configurable
enumerable

  • 可配置 – 如果false,则无法删除或更改该属性。默认为false.
  • 可枚举 – 如果true,则该属性在循环中迭代。默认为
    false.
  • 可写 – 如果false,则不能更改属性的值
索引.js
const obj2 = {}; Object.defineProperties(obj2, { country: { value: 'Germany', writable: true, // 👈️ set property to writable configurable: true, enumerable: true, }, }); console.log(obj2); obj2.country = 'Austria'; console.log(obj2.country); // 👉️ "Austria"

我们还将enumerableconfigurable属性设置为true

  • configurable设置为 时true,可以删除该属性。该属性的默认值为false

  • enumerable设置为时true,该属性将在循环中迭代。该属性的默认值为false

想了解更多关于使用 Object.defineProperty() 方法的信息吗 查看这些资源: 如何在 JavaScript 中将键/值对添加到对象如何在 JavaScript 中重命名对象键如何在 JavaScript 中清除对象



将对象传递给Object.freeze方法

如果将对象或数组传递给Object.freeze,则不能:

  • 向其添加新属性或元素
  • 删除现有属性
  • 更改现有属性

解决此问题的最佳方法是创建对象或数组的副本并更改副本。

使用带有冻结状态对象和数组的第三方库

如果您使用某些已冻结对象或数组的第三方库state,您很可能不应该state直接改变该对象。

该库可能会导出一个应该用于更改state.

使用 React.js 等库时,不应直接修改状态。

相反,该库提供了可用于更改状态的方法和挂钩。

如果您从库中获取的对象被标记为只读,那么这是有意为之,因为用户不应直接修改它们。

以下是使用 React.js 时如何更改状态数组或状态对象的指南:

结论

要解决“无法分配给对象的只读属性”错误:

  1. 确保在设置属性之前创建冻结对象或数组的副本。
  2. 如果您使用 ,请将该writable属性设置为trueObject.defineProperties
  3. 确保不要修改 React.js 等库中的状态对象,并使用内置方法设置状态。