当我们尝试更改已冻结对象的属性或使用
Object.defineProperties()
定义属性时,会发生错误“Cannot assign to read only property of Object”。
要解决该错误,需要创建对象或数组的副本,或将属性设置为可写。
以下是发生上述错误的 3 个示例。
const
obj = {
name
:
'James'
,
Object
.
freeze
(obj);
obj.
name
=
'Fql'
;
const
arr = [
'a'
,
'b'
,
'c'
];
Object
.
freeze
(arr);
arr[
0
] =
'z'
;
const
obj2 = {};
Object
.
defineProperties
(obj2, {
country
: {
value
:
'Germany'
,
obj2.
country
=
'Austria'
;
前两个错误的发生是因为对象或数组已被
Object.freeze()
方法冻结。
错误的常见原因
“Cannot assign to read only property of object”错误的最常见原因是:
试图将属性分配给冻结的对象或数组。
使用
Object.defineProperties
时忘记将
writable
设置为
true
。
在使用第三方库(例如 React.js)时尝试就地修改状态对象或数组。
创建数组或对象的副本
无法再更改冻结的对象,但我们可以创建数组或对象的副本并更改副本。
const
obj = {
name
:
'James'
,
Object
.
freeze
(obj);
const
objCopy = {...obj};
objCopy.
name
=
'Fql'
;
console
.
log
(objCopy);
const
arr = [
'a'
,
'b'
,
'c'
];
Object
.
freeze
(arr);
const
arrCopy = [...arr];
arrCopy[
0
] =
'z'
;
console
.
log
(arrCopy);
我们使用扩展语法
...
创建对象和数组的副本,因此我们可以更改它们。
尝试对只读数组进行排序
当我们尝试对只读数组进行排序时也会发生此错误,因为
Array.sort()
方法会在适当的位置对数组进行排序。
const
arr = [
'a'
,
'b'
,
'c'
];
Object
.
freeze
(arr);
arr.
sort
();
要解决该错误,请创建数组的副本并对副本进行排序。
const
arr = [
'a'
,
'b'
,
'c'
];
Object
.
freeze
(arr);
const
arrCopy = [...arr];
arrCopy.
sort
();
console
.
log
(arrCopy);
我们使用扩展语法
...
创建数组的副本,并在副本上调用
sort()
方法。
现在我们不再试图改变只读数组。
我们还可以使用
Array.slice()
方法创建冻结数组的浅表副本。
const
arr = [
'a'
,
'b'
,
'c'
];
Object
.
freeze
(arr);
const
arrCopy = arr.
slice
();
arrCopy.
sort
();
console
.
log
(arrCopy);
当不带任何参数调用
slice()
方法时,它返回原始数组的浅表副本。
如果使用
Object.defineProperties()
,将 writable 设置为 true
如果在使用
Object.defineProperties
方法时出现错误,如果要更改其值,请将属性设置为可写。
const
obj2 = {};
Object
.
defineProperties
(obj2, {
country
: {
value
:
'Germany'
,
writable
:
true
,
obj2.
country
=
'Austria'
;
console
.
log
(obj2.
country
);
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
);
我们还将可枚举和可配置属性设置为
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 等库中的状态对象,并使用内置方法设置状态。
JavaScript 中 Unexpected end of JSON input 错误
你理解Javascript的闭包吗?
如何在 JavaScript 中将集合set转换为 JSON
如何在 JavaScript 中存储键值数组
你需要知道的关于Javascript 中的 Let 关键词的一切
在 JavaScript 中获取字符串的最后 N 个字符
JavaScript 中如何检查函数是否定义
在 JavaScript 中从数组中删除重复的内容
在 JavaScript 中将数字四舍五入到小数点后两位