JavaScript 中 Cannot assign to read only property of Object 错误
当我们尝试更改已冻结对象的属性或使用 Object.defineProperties()
定义属性时,会发生错误“Cannot assign to read only property of Object”。
要解决该错误,需要创建对象或数组的副本,或将属性设置为可写。
以下是发生上述错误的 3 个示例。
// 👇️ 使用 OBJECTS 👇️
const obj = {
name: 'James',
};
Object.freeze(obj);
// ⛔️ Error: Cannot assign to read only property 'name' of object '#<Object>'
obj.name = 'Fql';
// ------------------------------------------------------
// 👇️ 使用 ARRAYS 👇️
const arr = ['a', 'b', 'c'];
Object.freeze(arr);
// ⛔️ Error: Cannot assign to read only property '0' of object '[object Array]'
arr[0] = 'z';
// ------------------------------------------------------
// 👇️ 使用 Object.defineProperties() 👇️
const obj2 = {};
Object.defineProperties(obj2, {
country: {
value: 'Germany',
// 👉️ 必须设置为 writable: true
// writable: true, // 👈️ 这里取消注释
},
});
// ⛔️ Error: Cannot assign to read only property 'country' of object '#<Object>'
obj2.country = 'Austria';
前两个错误的发生是因为对象或数组已被 Object.freeze()
方法冻结。
错误的常见原因
“Cannot assign to read only property of object”错误的最常见原因是:
- 试图将属性分配给冻结的对象或数组。
-
使用
Object.defineProperties
时忘记将 writable 设置为 true。 - 在使用第三方库(例如 React.js)时尝试就地修改状态对象或数组。
创建数组或对象的副本
无法再更改冻结的对象,但我们可以创建数组或对象的副本并更改副本。
// ✅ 使用 OBJECTS
const obj = {
name: 'James',
};
Object.freeze(obj);
const objCopy = {...obj}; // 👈️ 创建副本
objCopy.name = 'Fql';
console.log(objCopy); // 👉️ {name: 'Fql'}
// --------------------------------------
// ✅ 使用 ARRAYS
const arr = ['a', 'b', 'c'];
Object.freeze(arr);
const arrCopy = [...arr]; // 👈️ 创建副本
arrCopy[0] = 'z';
console.log(arrCopy); // 👉️ ['z', 'b', 'c']
我们使用扩展语法 ...
创建对象和数组的副本,因此我们可以更改它们。
尝试对只读数组进行排序
当我们尝试对只读数组进行排序时也会发生此错误,因为 Array.sort()
方法会在适当的位置对数组进行排序。
const arr = ['a', 'b', 'c'];
Object.freeze(arr);
// ⛔️ TypeError: Cannot assign to read only property '0' of object '[object Array]'
arr.sort();
要解决该错误,请创建数组的副本并对副本进行排序。
const arr = ['a', 'b', 'c'];
Object.freeze(arr);
// 👇️ 创建副本
const arrCopy = [...arr];
// 👇️ 对副本排序
arrCopy.sort();
console.log(arrCopy); // 👉️ [ 'a', 'b', 'c' ]
我们使用扩展语法 ...
创建数组的副本,并在副本上调用 sort()
方法。
现在我们不再试图改变只读数组。
我们还可以使用 Array.slice()
方法创建冻结数组的浅表副本。
const arr = ['a', 'b', 'c'];
Object.freeze(arr);
// 👇️ 创建数组的浅表副本
const arrCopy = arr.slice();
arrCopy.sort();
console.log(arrCopy); // 👉️ [ 'a', 'b', 'c' ]
当不带任何参数调用 slice()
方法时,它返回原始数组的浅表副本。
如果使用 Object.defineProperties()
,将 writable 设置为 true
如果在使用 Object.defineProperties
方法时出现错误,如果要更改其值,请将属性设置为可写。
const obj2 = {};
Object.defineProperties(obj2, {
country: {
value: 'Germany',
writable: true, // 👈️ 将属性设置为可写
},
});
obj2.country = 'Austria';
console.log(obj2.country); // 👉️ "Austria"
country
属性设置为可写,因此可以更改。
使用
Object.defineProperties()
方法时,可写参数默认为 false。
如果我们希望能够更改属性的值,请将 writable
显式设置为 true。
我们可能必须在对象上设置的其他属性是可配置和可枚举的:
- configurable - 如果为 false,则无法删除或更改该属性。 默认为假。
- enumerable - 如果为 true,则该属性在循环中迭代。 默认为假。
- writable - 如果为 false,则不能更改属性的值
const obj2 = {};
Object.defineProperties(obj2, {
country: {
value: 'Germany',
writable: true, // 👈️ 将属性设置为可写
configurable: true,
enumerable: true,
},
});
console.log(obj2);
obj2.country = 'Austria';
console.log(obj2.country); // 👉️ "Austria"
我们还将可枚举和可配置属性设置为 true。
当 configurable
设置为 true 时,可以删除该属性。 该属性的默认值为 false。
当 enumerable
设置为 true 时,该属性将在循环中迭代。 该属性的默认值为 false。
将对象传递给 Object.freeze 方法
如果将对象或数组传递给 Object.freeze
,则不能:
- 向其添加新属性或元素
- 删除现有属性
- 更改现有属性
解决此问题的最佳方法是创建对象或数组的副本并更改副本。
使用带有冻结状态对象和数组的第三方库
如果我们使用某些已冻结状态对象或数组的第三方库,我们很可能不应该直接改变 state
对象。
该库可能会导出一个应该用于更改 state
的方法。
使用 React.js 等库时,不应直接修改状态。
相反,该库提供了可用于更改状态的方法和钩子。
如果我们从库中获取的对象被标记为只读,那么这是有意为之,因为用户不应直接修改它们。
总结
要解决“Cannot assign to read only property of Object”错误:
- 确保在设置属性之前创建冻结对象或数组的副本。
-
如果我们使用
Object.defineProperties
,请将可写属性设置为 true。 - 确保不要修改 React.js 等库中的状态对象,并使用内置方法设置状态。
相关文章
使用 CSS 和 JavaScript 制作文本闪烁
发布时间:2023/04/28 浏览次数:146 分类:CSS
-
本文提供了使用 CSS、JavaScript 和 jQuery 使文本闪烁的详细说明。
在 PHP 变量中存储 Div Id 并将其传递给 JavaScript
发布时间:2023/03/29 浏览次数:69 分类:PHP
-
本文教导将 div id 存储在 PHP 变量中并将其传递给 JavaScript 代码。
在 JavaScript 中从字符串中获取第一个字符
发布时间:2023/03/24 浏览次数:93 分类:JavaScript
-
在本文中,我们将看到如何使用 JavaScript 中的内置方法获取字符串的第一个字符。
在 JavaScript 中获取字符串的最后一个字符
发布时间:2023/03/24 浏览次数:141 分类:JavaScript
-
本教程展示了在 javascript 中获取字符串最后一个字符的方法