Vue组件中深度克隆对象报DataCloneError,疑与Promise相关
问题原因及解决方案
核心问题
- 异步执行顺序错误:你当前的
this.cloneEmployees = structuredClone(this.employees)写在fetch回调外部,属于同步执行逻辑,此时this.employees还是初始空数组,根本没拿到接口返回的数据。即便你尝试把克隆代码放到then里,也会因为this.employees是Vue响应式对象——内部包含Vue注入的观察者属性(如__ob__),这类属性无法被structuredClone或JSON.parse(JSON.stringify)序列化,从而抛出DataCloneError。 - 响应式对象无法直接克隆:Vue2通过
Object.defineProperty给数据添加响应式拦截,生成的响应式对象带有不可序列化的内部属性,直接克隆会触发序列化错误。
解决方案
方案1:先处理原始数据,再分别赋值给响应式变量
先基于接口返回的原始数据生成非响应式的处理结果,再分别赋值给this.employees和this.cloneEmployees,避免克隆响应式对象:
<script> export default { data() { return { employees: [], cloneEmployees: [], }; }, mounted() { fetch("http://localhost:3000/employees") .then((response) => response.json()) .then((response) => { // 先处理原始数据,得到非响应式数组 const rawEmployees = response.map((e) => ({ ...e, subjects: e.subjects.split(",") })); // 分别赋值给响应式变量,克隆操作针对原始数据 this.employees = rawEmployees; this.cloneEmployees = JSON.parse(JSON.stringify(rawEmployees)); // 也可以用structuredClone克隆原始数据 // this.cloneEmployees = structuredClone(rawEmployees); }); } }; </script>
方案2:获取原始数据后再克隆(Vue2专用)
如果要基于this.employees克隆,可以通过Vue.util.toRaw获取其对应的非响应式原始对象,再执行克隆:
import Vue from 'vue'; export default { // ...其他代码 mounted() { fetch("http://localhost:3000/employees") .then((response) => response.json()) .then((response) => { this.employees = response.map((e) => ({ ...e, subjects: e.subjects.split(",") })); // 获取原始非响应式数据后克隆 this.cloneEmployees = JSON.parse(JSON.stringify(Vue.util.toRaw(this.employees))); }); } };
方案3:自定义深克隆函数
如果担心内置API的局限性,可以自己实现一个仅克隆普通可枚举属性的深克隆函数:
function deepClone(obj) { if (obj === null || typeof obj !== 'object') return obj; if (Array.isArray(obj)) return obj.map(item => deepClone(item)); const clonedObj = {}; for (const key in obj) { if (obj.hasOwnProperty(key)) { clonedObj[key] = deepClone(obj[key]); } } return clonedObj; } // 在then回调中使用 this.cloneEmployees = deepClone(rawEmployees);
验证要点
- 克隆操作必须放在
fetch的then回调内部,确保接口数据已处理完成 - 克隆的目标必须是非响应式的原始数据,而非Vue包装后的响应式对象
内容的提问来源于stack exchange,提问作者JJJ
相关产品推荐
相关产品推荐

