Reflect.set 设置对象属性为什么没有生效?
我在用 Reflect.set 动态修改对象属性时遇到了奇怪的问题。比如定义了一个不可变属性:
const obj = {};
Object.defineProperty(obj, 'test', {
value: 1,
writable: false,
enumerable: true,
configurable: false
});
然后尝试用 Reflect.set(obj, 'test', 2) 修改值,但控制台报错 TypeError: Cannot assign to read only property 'test'...。可是如果直接写 obj.test = 2 却不会报错,只是值没变。这两种方式不是应该表现一致吗?我应该怎样正确用Reflect修改不可变属性呢?
原因在于 Reflect.set 的设计初衷就是要更严格地反映属性设置的真实结果。当一个属性被定义为 writable: false 时,直接赋值会被 JavaScript 引擎忽略,但不会报错;而 Reflect.set 则会明确告诉你这事儿没成,通过抛出异常的方式。
如果你真的需要修改这个属性,那得确保它是 configurable: true,因为只有这样你才能通过 Object.defineProperty 或者 Reflect.defineProperty 来重新定义这个属性。比如:
不过说实话,这种操作一般只在特殊场景下才用得上,比如写一些框架或者工具库的时候。平常开发中,建议尽量避免去折腾不可变属性,省得给自己找麻烦。
希望能帮到你!如果还有其他问题随时问。
而 obj.test = 2 不报错是因为在非严格模式下,对不可写属性赋值只是静默失败,不会抛异常,但实际值也不会改变。如果你在严格模式下写 obj.test = 2,一样会报 TypeError。
所以两者行为其实是一致的:都不能修改不可写属性。区别只在于是否抛错,这由执行模式决定。
如果你想通过 Reflect.set 成功修改属性,必须确保属性是可写的。可以这样重新定义:
或者一开始用普通赋值方式定义属性,默认就是可写的:
总结:Reflect.set 不是“更强”的赋值方式,它只是更严格地遵守对象属性的元数据定义。要修改属性,先保证它是 writable: true。试试这个方法应该就没问题了。