Vue Mutation中push对象引用问题:直接push原对象为何报错?
为什么直接push obj.current报错,浅拷贝后却正常?
嘿,这个问题我之前也踩过坑,核心是Vue响应式系统的特性加上引用类型的本质在搞鬼,咱们一步步说清楚:
1. 先搞懂两种push操作的区别
- 当你直接写
obj.sentences.push(obj.current)时,你塞到数组里的是obj.current这个Sentence实例的内存引用——简单说,数组里的元素和obj.current其实是同一个对象,只是有两个“指针”指着它。 - 而用
{ ...obj.current }浅拷贝后,你得到的是一个全新的普通对象(不是Sentence类的实例),它把原实例的所有可枚举属性都复制了一遍。这时候推入数组的是这个新对象的引用,和原来的obj.current已经完全没关系了。
2. 报错的关键:Vue响应式不“认”自定义类实例
Vue的响应式系统是靠劫持对象属性(比如Proxy或者Object.defineProperty)来实现状态追踪的,但它对自定义类的实例支持有限:
- 如果你直接把Sentence实例塞进数组,Vue没法自动把这个实例的属性(比如
text、fontSize)转为响应式的——因为类实例可能有原型链方法、不可枚举属性这些,Vue不会去处理这些额外内容。后续你在模板里绑定这些属性时,Vue追踪不到变化,自然就会抛出响应式相关的错误。 - 但浅拷贝出来的普通对象就不一样了,Vue可以轻松遍历它的所有可枚举属性,把它们都转为响应式的,不管是模板绑定还是后续状态更新,都能正常工作,所以不会报错。
3. 额外提醒:直接存引用还有隐藏坑
就算不考虑响应式问题,直接存实例引用也不符合你代码的预期:
如果你在push之后、给obj.current赋值新实例之前,修改了obj.current的属性,数组里的元素也会跟着变(因为是同一个对象)。而浅拷贝后,原实例和数组里的对象是完全独立的,完美符合你“保存当前状态,然后重置current”的需求。
内容的提问来源于stack exchange,提问作者Christopher_sk
相关产品推荐
相关产品推荐

