Vue中深克隆的3种实现方案

 更新时间:2026年04月28日 08:30:35   作者:前端那点事  
本文介绍了三种Vue开发中常用的深克隆实现方法,分别适用于不同场景,方案一适用于普通对象和数组,方案二适用于所有数据类型,方案三专门适配Vue的响应式数据,每种方案都有其优点和缺点,开发时可根据具体需求选择合适的的方法,提高开发效率,需要的朋友可以参考下

深克隆(深拷贝)的核心是复制一个对象/数组,且拷贝后的对象与原对象完全独立,修改拷贝对象不会影响原对象(包括嵌套层级的属性/元素)。在Vue开发中,深克隆常用于处理响应式数据(如ref、reactive创建的数据),避免因浅拷贝导致的响应式异常,以下是3种实用实现方案,从简单到完善,覆盖不同场景。

一、核心前提:浅克隆 vs 深克隆(必懂区别)

先明确浅克隆与深克隆的差异,避免混淆:

  • 浅克隆:仅复制对象的第一层属性,嵌套的对象/数组仍指向原引用(修改嵌套内容会影响原对象),如Object.assign()、扩展运算符(...)。
  • 深克隆:复制对象的所有层级(包括嵌套的对象、数组、函数等),拷贝后与原对象完全脱离引用,互不影响(这是Vue开发中常用的方式)。

Vue中注意点:对于reactive创建的响应式对象,直接克隆会丢失响应式特性,需特殊处理;ref对象需先获取.value再克隆。

二、方案1:基础版深克隆(适配普通对象/数组,无复杂类型)

适用于:普通对象、数组,无函数、Date、RegExp等复杂类型,代码简洁,上手快。

核心逻辑:利用JSON.stringify()将对象转为字符串,再用JSON.parse()转回对象,实现深度拷贝(本质是序列化+反序列化)。

// 基础版深克隆(Vue中可直接使用,适配简单数据)
function deepCloneBasic(obj) {
  // 处理null和非对象/数组类型(直接返回,无需克隆)
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }
  // 利用JSON序列化+反序列化实现深克隆
  return JSON.parse(JSON.stringify(obj));
}

// Vue中测试示例(普通数据)
const obj = { name: 'Vue', info: { version: '3.4.21' }, list: [1, 2, 3] };
const cloneObj = deepCloneBasic(obj);

// 修改拷贝对象,原对象不受影响
cloneObj.info.version = '3.5.0';
cloneObj.list.push(4);
console.log(obj.info.version); // 3.4.21(原对象不变)
console.log(obj.list); // [1,2,3](原对象不变)

优点:代码简洁,无需复杂逻辑,适配大部分简单场景;

缺点:无法克隆函数、Date、RegExp、undefined、Symbol等复杂类型(会丢失或变形),不适合包含这些类型的数据。

三、方案2:完善版深克隆(适配所有类型,通用推荐)

适用于:所有数据类型(对象、数组、函数、Date、RegExp等),解决基础版的缺陷,是Vue开发中最常用的通用方案。

核心逻辑:递归遍历对象/数组,对不同类型的数据分别处理,确保所有层级都被深度拷贝,不丢失类型和属性。

// 完善版深克隆(适配所有类型,Vue通用)
function deepClonePerfect(obj) {
  // 1. 处理null和非对象类型(直接返回)
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }

  // 2. 处理Date类型(避免Date被转为普通对象)
  if (obj instanceof Date) {
    return new Date(obj);
  }

  // 3. 处理RegExp类型(保留正则的修饰符)
  if (obj instanceof RegExp) {
    return new RegExp(obj.source, obj.flags);
  }

  // 4. 处理数组和对象(区分数组和普通对象)
  // 创建一个与原对象类型一致的空容器(数组→数组,对象→对象)
  const cloneObj = Array.isArray(obj) ? [] : {};

  // 5. 递归遍历所有属性,深度拷贝
  for (let key in obj) {
    // 只拷贝对象自身的属性(排除原型链上的属性)
    if (obj.hasOwnProperty(key)) {
      // 递归克隆子属性(嵌套对象/数组)
      cloneObj[key] = deepClonePerfect(obj[key]);
    }
  }

  return cloneObj;
}

// Vue中测试示例(复杂数据)
const complexObj = {
  name: '深克隆',
  date: new Date(),
  reg: /vue/g,
  func: () => console.log('vue'),
  info: { a: 1, b: { c: 2 } },
  list: [1, [2, 3]]
};

const cloneComplex = deepClonePerfect(complexObj);
cloneComplex.info.b.c = 100;
cloneComplex.list[1].push(4);
cloneComplex.date.setFullYear(2025);

console.log(complexObj.info.b.c); // 2(原对象不变)
console.log(complexObj.list[1]); // [2,3](原对象不变)
console.log(complexObj.date.getFullYear()); // 2024(原对象不变)
console.log(cloneComplex.func()); // vue(函数正常克隆)

优点:适配所有数据类型,克隆彻底,无数据丢失,满足Vue中复杂数据的克隆需求;

缺点:代码稍复杂,无需额外依赖,可直接封装到Vue项目中复用。

四、方案3:Vue专属深克隆(适配响应式数据,推荐)

适用于:Vue2/Vue3的响应式数据(ref、reactive创建的数据),解决“克隆后丢失响应式”的问题,结合Vue内置API,更贴合Vue开发场景。

核心逻辑:利用Vue内置的reactive、ref API,克隆后重新创建响应式对象,确保克隆后的数据仍保持响应式特性。

1. Vue3 专属实现(适配ref、reactive)

<script setup>
import { ref, reactive, isRef, isReactive, toRaw } from 'vue'

// Vue3专属深克隆(保留响应式)
function deepCloneVue3(obj) {
  // 处理ref对象:先获取原始值,克隆后重新创建ref
  if (isRef(obj)) {
    const rawValue = toRaw(obj.value); // 转为原始值(避免响应式干扰)
    const cloneValue = deepClonePerfect(rawValue); // 用完善版克隆原始值
    return ref(cloneValue); // 重新创建ref,保留响应式
  }

  // 处理reactive对象:先获取原始值,克隆后重新创建reactive
  if (isReactive(obj)) {
    const rawObj = toRaw(obj); // 转为原始对象
    const cloneObj = deepClonePerfect(rawObj); // 深度克隆
    return reactive(cloneObj); // 重新创建reactive,保留响应式
  }

  // 非响应式数据,直接用完善版克隆
  return deepClonePerfect(obj);
}

// 测试示例
const reactiveObj = reactive({ name: 'Vue3', info: { age: 5 } });
const refObj = ref({ a: 1, b: [2, 3] });

// 克隆响应式数据
const cloneReactive = deepCloneVue3(reactiveObj);
const cloneRef = deepCloneVue3(refObj);

// 修改克隆对象,原对象不受影响,且克隆对象仍有响应式
cloneReactive.info.age = 10;
cloneRef.value.b.push(4);

console.log(reactiveObj.info.age); // 5(原对象不变)
console.log(refObj.value.b); // [2,3](原对象不变)
console.log(cloneReactive.info.age); // 10(克隆对象响应式正常)
</script>

2. Vue2 专属实现(适配data、ref、reactive)

// Vue2专属深克隆(保留响应式,需引入Vue)
import Vue from 'vue'

function deepCloneVue2(obj) {
  // 处理Vue2的响应式对象(data中定义的对象、Vue.observable创建的对象)
  if (Vue.isReactive(obj) || Vue.isVue(obj)) {
    // 用Vue.extend创建临时组件,通过props传递数据,实现响应式克隆
    const TempComponent = Vue.extend({
      props: Object.keys(obj),
      render: function() {}
    });
    const instance = new TempComponent({ propsData: obj });
    return instance._props;
  }

  // 处理ref对象(Vue2的ref需通过.value访问)
  if (obj && obj._isRef) {
    const cloneValue = deepClonePerfect(obj.value);
    return Vue.ref(cloneValue);
  }

  // 非响应式数据,用完善版克隆
  return deepClonePerfect(obj);
}

// 测试示例(Vue2)
const vue2Reactive = Vue.observable({ name: 'Vue2', list: [1, 2] });
const cloneVue2 = deepCloneVue2(vue2Reactive);
cloneVue2.list.push(3);
console.log(vue2Reactive.list); // [1,2](原对象不变)
console.log(cloneVue2.list); // [1,2,3](克隆对象响应式正常)

优点:专门适配Vue响应式数据,克隆后不丢失响应式特性,贴合Vue开发场景;

缺点:依赖Vue内置API,需区分Vue2和Vue3版本。

五、Vue中深克隆的注意事项

  • 克隆响应式数据时,不可直接用基础版(JSON方式),会丢失响应式特性,需用Vue专属方案;
  • Vue3中,reactive对象克隆前需用toRaw()转为原始对象,否则会因响应式代理导致克隆异常;
  • 避免克隆Vue组件实例、Vuex状态等特殊对象,这类对象克隆后可能无法正常使用;
  • 若项目中频繁使用深克隆,可将完善版/Vue专属版封装为全局工具函数(如utils/clone.js),方便复用;
  • 简单场景(无复杂类型、非响应式数据)可直接用基础版,复杂场景优先用完善版,响应式数据用Vue专属版。

六、总结(方案选择建议)

  1. 简单场景(普通对象/数组,无复杂类型):方案1(基础版),简洁高效;
  2. 通用场景(所有数据类型,非响应式):方案2(完善版),克隆彻底,无数据丢失;
  3. Vue开发场景(响应式数据):方案3(Vue专属版),保留响应式,贴合Vue特性。

实际开发中,可根据数据类型和是否为响应式,选择对应的方案,建议将方案2和方案3封装为全局工具,提升开发效率。

以上就是Vue中深克隆的3种实现方案的详细内容,更多关于Vue深克隆实现方案的资料请关注脚本之家其它相关文章!

相关文章

  • Element-ui/Element-plus Vue报错问题及解决

    Element-ui/Element-plus Vue报错问题及解决

    这篇文章主要介绍了Element-ui/Element-plus Vue报错问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-01-01
  • 在Vue项目中优化字体文件的加载和缓存的常用方法

    在Vue项目中优化字体文件的加载和缓存的常用方法

    在现代 Web 开发中,字体文件通常是页面加载时间的重要因素之一,特别是在字体文件较大或网络环境不佳的情况下,用户体验可能会受到影响,本文将详细探讨如何在 Vue.js 项目中优化字体文件的加载和缓存,以提高页面性能,需要的朋友可以参考下
    2024-09-09
  • vue中解决el-date-picker更改样式不生效问题

    vue中解决el-date-picker更改样式不生效问题

    在使用Vue.js进行前端开发的过程中,Element UI 是一个非常流行的UI库,它提供了一套完整的组件来快速搭建美观的用户界面,但是我们经常遇到一个问题使用Element UI提供的el-date-picker组件时,尝试自定义其样式却无法生效,所以本文给大家介绍如何解决这个问题
    2024-10-10
  • 在Vue中使用Avue、配置过程及实际应用小结

    在Vue中使用Avue、配置过程及实际应用小结

    在项目中遇到通过点击加号实现输入框的增加、以及对该输入框的输入内容进行验证,通过这些诱导因素创作的这篇文章,本文重点给大家介绍在Vue中使用Avue、配置过程以及实际应用,需要的朋友可以参考下
    2022-10-10
  • vue引入ueditor及node后台配置详解

    vue引入ueditor及node后台配置详解

    这篇文章主要介绍了vue引入ueditor及node后台配置详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-01-01
  • vue 手机物理监听键+退出提示代码

    vue 手机物理监听键+退出提示代码

    这篇文章主要介绍了vue 手机物理监听键+退出提示代码,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • vue+electron 自动更新的实现代码

    vue+electron 自动更新的实现代码

    这篇文章主要介绍了vue+electron 自动更新的实现代码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2024-02-02
  • 如何使用fetchEventSource实现sse流式请求

    如何使用fetchEventSource实现sse流式请求

    这篇文章主要介绍了如何使用fetchEventSource实现sse流式请求问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • 详解vue 模拟后台数据(加载本地json文件)调试

    详解vue 模拟后台数据(加载本地json文件)调试

    本篇文章主要介绍了详解vue 模拟后台数据(加载本地json文件)调试,具有一定的参考价值,有兴趣的可以了解一下
    2017-08-08
  • vue-cli3项目展示本地Markdown文件的方法

    vue-cli3项目展示本地Markdown文件的方法

    这篇文章主要介绍了vue-cli3项目展示本地Markdown文件的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-06-06

最新评论