You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vuex存储JavaScript类实例后自动转为普通对象的问题

解决Vuex存储类实例变为普通对象的问题

这个坑我之前踩过!你遇到的问题本质是Vue的响应式系统会自动把存入Vuex state的类实例转换成普通响应式对象,导致类的原型链、getter/setter以及方法全部丢失。

为什么mutation里的两次console.log都显示正常?因为刚把实例push进数组时,Vue还没来得及对这个新对象做响应式处理,等你后续通过getter访问时,Vue已经完成了响应式转换,把实例变成了普通对象。

下面给你两种实用的解决方案,根据你的需求选:

方案一:在Getter中重构类实例(推荐,支持响应式)

如果需要Coin实例的属性变化能触发视图更新,那就把state里存储的普通对象在getter中重新构造成Coin实例:

修改你的Vuex模块的getters:

const getters = {
  ownedCoins (state) {
    // 把每个普通对象重新转为Coin实例
    return state.ownedCoins.map(coinObj => {
      return new Coin(coinObj._name, coinObj._amount, coinObj._priceBought)
    })
  },
}

这样每次通过this.$store.getters.ownedCoins获取的都是完整的Coin实例,而且state里的普通对象是响应式的,属性变化会自动触发getter重新计算,视图也会更新。

方案二:标记实例为非响应式(适合不需要响应式的场景)

如果你的Coin实例不需要响应式(比如属性不会动态变化,或者不需要视图跟着更新),可以用Vue的markRaw方法把实例标记为“不需要被响应式处理”,这样Vuex就会保留原始的类实例:

Vue 3写法:

import { markRaw } from 'vue'

// 创建实例时标记为非响应式
const coin = markRaw(new Coin(
  this.formAdd.coin,
  this.formAdd.amount,
  this.formAdd.price
))
this.$store.commit('ADD_COIN', coin)

Vue 2写法:

// Vue2里用Vue.util.markRaw
const coin = Vue.util.markRaw(new Coin(
  this.formAdd.coin,
  this.formAdd.amount,
  this.formAdd.price
))
this.$store.commit('ADD_COIN', coin)

这个方法的好处是直接保留原始实例,但代价是实例的属性变化不会触发视图更新,按需选择就好。

补充说明

你可以测试一下:在mutation的ADD_COIN里加一个setTimeout,延迟一点再打印state.ownedCoins,就会发现实例已经变成普通对象了——这就是Vue的响应式系统在后台处理的结果。

内容的提问来源于stack exchange,提问作者Pascal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:45:20