js数组和对象浅拷贝、深拷贝的几种方法 ,js数组、对象深浅拷贝

本文详细介绍了JavaScript中数组和对象的深浅拷贝方法,包括ES5、ES6扩展运算符、Array.from及JSON操作。探讨了各种拷贝方式的优缺点,帮助开发者在不同场景下选择合适的技术。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我们经常会用到对一个数组或对象的拷贝,而不是操作原数组或对象。下面总结几种js数组和对象深浅拷贝的几种方式:

一、es5实现数组和对象的浅拷贝与深拷贝

1.数组和对象浅拷贝:

function shallowCopy(source){
    if (typeof source !== 'object') {
        throw TypeError('the source must be an array or object')
    }
    let target = Array.isArray(source) ? [] : {};
    for (let key in source){
        //原型链上的属性不拷贝
        if(source.hasOwnProperty(key)){
            target[key] = source[key]
        }
    }
    return target;
}

2.数组和对象深拷贝:

function deepCopy(source){
    if(typeof source !== 'object'){
        throw TypeError('the source must be an array or object');
    }
    let target = Array.isArray(source) ? [] :{};
    for(let key in source){
        if(source.hasOwnProperty(key)){//不拷贝原型链上的属性
            if(typeof source[key] === 'object'){
                //递归调用多维数组、对象
                target[key] = deepCopy(source[key]);
            }else{
                target[key] = source[key];
            }
        }
    }
    return target;
}

二、使用扩展运算符[...]实现浅拷贝

es6中扩展运算符是实现数组和对象浅拷贝的最简单的实现方式

浅拷贝:其实我下面集成一下反而显得繁琐不简洁,使用的时候根据数组或对象直接【...source】{...source}才是最简洁的。

function shallowCopy(source){
    if(typeof source !== 'object'){
        throw TypeError('the source must be an array or object');
    }
    if(Array.isArray(source)){
        return [...source];
    }else{
        return {...source};
    }
}

深拷贝:这个玩意用来实现浅拷贝是最好的,用这个实现深拷贝?想啥呢!!!

三、使用Array.from实现数组的浅拷贝和深拷贝

Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)。实际应用中,常见的类似数组的对象是 DOM 操作返回的 NodeList 集合,以及函数内部的arguments对象。Array.from都可以将它们转为真正的数组。

扩展运算符背后调用的是遍历器接口(Symbol.iterator),如果一个对象没有部署这个接口,就无法转换。Array.from方法还支持类似数组的对象。所谓类似数组的对象,本质特征只有一点,即必须有length属性。因此,任何有length属性的对象,都可以通过Array.from方法转为数组,而此时扩展运算符就无法转换。

数组浅拷贝:Array.from实现浅拷贝其实跟用扩展运算符原理类似

function shallowCopy(source) {
    if(Array.isArray(source)){
        return Array.from(source);
    }else{
        throw TypeError('the source must be an array');
    }
}

数组深拷贝:利用Array.from的第二个参数回调函数进行递归调用

Array.from还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。

Array.from(arrayLike, x => x * x);
// 等同于
Array.from(arrayLike).map(x => x * x);

Array.from([1, 2, 3], (x) => x * x)
// [1, 4, 9]

所以可以利用这个map实现数组深拷贝:

function deepCopy(source) {
    return Array.isArray(source) ? Array.from(source, arguments.callee) : source;
}

四、深拷贝并处理循环引用

const sampleDeepClone= (obj, hash = new WeakMap()) => {
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }
  if (obj instanceof Date) {
    return new Date(obj);
  }
  if (obj instanceof RegExp) {
    return new RegExp(obj);
  }

  if (hash.has(obj)) {
    return hash.get(obj);
  }

  let cloneObj = new obj.constructor();
  hash.set(obj, cloneObj);

  // 对象和对象
  for (const [key, value] of Object.entries(obj)) {
    cloneObj[key] = sampleDeepClone(value);
  }
  return cloneObj;
};

五、数组和对象深拷贝黑科技:JSON.parse()和JSON.stringify()

function deepCopy(source){
    return JSON.parse(JSON.stringify(source));
}

但是这个黑科技是有缺点的:具体见 详情

  1. 如果对象中有函数如({mm:function(){...}})不会被拷贝
  2. 会将对象原型链上的属性一并给拷贝了

<think>好的,我现在需要回答用户关于如何实现数组对象的深复制浅复制的相关问题。首先,我得明确用户的需求,他们想了解在不同编程语言中如何复制数组对象,特别是深浅拷贝的区别实现方法。 根据用户提供的引用内容,我看到有几个引用涉及到不同语言的拷贝方法。比如引用[1]提到Python的deepcopy()会递归复制所有子对象,直到基本数据类型。引用[4]是Java的示例,展示了全拷贝部分拷贝的实现。引用[2][5]讨论了JavaScript的数组合并对象数组的复制。还有引用[3]提到C++的const成员函数vector创建数组对象。 我需要先整理深浅拷贝的基本概念,然后分别针对不同语言给出示例。浅拷贝只复制引用,深拷贝复制对象本身。用户可能需要具体代码示例,所以每种语言最好都有浅拷贝深拷贝的代码,并解释区别。 在Python中,浅拷贝可以用列表的切片或者copy模块的copy(),而深拷贝用copy.deepcopy()。Java中的数组拷贝可以使用Arrays.copyOf()或System.arraycopy(),对于对象数组则需要手动深拷贝。JavaScript中,浅拷贝可以用扩展运算符或slice(),深拷贝可能需要JSON方法或者递归函数。C++中,浅拷贝是默认的,深拷贝需要自定义拷贝构造函数或重载赋值运算符。 要注意用户提供的引用中的代码示例,比如引用[4]的Java数组拷贝方法,可以引用作为例子。同时,引用[1]的递归深拷贝机制也需要提及。另外,用户可能希望了解不同语言间的实现差异,所以需要分语言说明。 最后,生成相关问题,比如深浅拷贝的应用场景、如何避免浅拷贝的问题等。确保回答结构清晰,分点说明,代码示例正确,并且正确引用用户提供的参考资料中的内容。</think># 数组对象深浅复制实现方法 ## 一、核心概念 深浅复制的核心区别在于对**嵌套对象**的处理方式: - **浅拷贝**:仅复制顶层元素,嵌套对象保持引用共享(修改会影响原对象) $$ \text{新数组} = [\text{原元素1}, \text{原元素2}, ..., \text{原嵌套对象引用}] $$ - **深拷贝**:完全复制所有层级对象,创建完全独立的新对象 $$ \text{新数组} = [\text{新元素1}, \text{新元素2}, ..., \text{新嵌套对象副本}] $$ ## 二、具体语言实现 ### 1. Python实现 ```python import copy # 原始数组(包含嵌套列表) original = [[1,2], {"key":3}, (4,5)] # 浅拷贝(三种方式) shallow1 = original.copy() shallow2 = list(original) shallow3 = original[:] # 深拷贝 deep_copy = copy.deepcopy(original) # 递归复制所有子对象[^1] ``` ### 2. Java实现 ```java // 基本类型数组深拷贝 int[] arr = {1,3,5}; int[] shallow = arr; // 浅拷贝 int[] deep1 = Arrays.copyOf(arr, arr.length); int[] deep2 = new int[3]; System.arraycopy(arr, 0, deep2, 0, 3); // 对象数组深拷贝(需元素实现Cloneable) class MyClass implements Cloneable { public Object clone() { return super.clone(); } } MyClass[] objArr = new MyClass[3]; MyClass[] deepObjArr = Arrays.stream(objArr) .map(obj -> obj.clone()) .toArray(MyClass[]::new); ``` ### 3. JavaScript实现 ```javascript // 浅拷贝(三种方式) const shallow1 = [...original]; const shallow2 = original.slice(); const shallow3 = Array.from(original); // 深拷贝(限制:无法复制函数/Symbol等特殊类型) const deepCopy = JSON.parse(JSON.stringify(original)); // 通过序列化实现[^5] ``` ### 4. C++实现 ```cpp // 浅拷贝(默认行为) vector<int> v1{1,2,3}; vector<int> v2 = v1; // 深拷贝(需自定义) template<typename T> vector<T> deepCopy(const vector<T>& source) { vector<T> newVec; newVec.reserve(source.size()); for(const auto& item : source) { newVec.push_back(make_shared<T>(*item)); // 智能指针深拷贝 } return newVec; } ``` ## 三、关键差异对比 | 特性 | 浅拷贝 | 深拷贝 | |----------------|-----------------------|-----------------------| | 内存消耗 | 低(共享嵌套对象) | 高(完全独立副本) | | 修改影响 | 双向影响 | 完全隔离 | | 时间复杂度 | $O(n)$ | $O(n*m)$(m为嵌套层级)| | 适用场景 | 临时快照、只读访问 | 数据隔离、持久化存储 | ## 四、最佳实践建议 1. 优先使用语言原生方法(如Python的copy模块[^1]、JS的扩展运算符[^2]) 2. 对象数组拷贝时注意元素的可克隆性(Java需实现Cloneable接口[^4]) 3. 嵌套层级超过3层时推荐深拷贝防止意外修改 4. 大数据量场景考虑性能优化(分块拷贝、惰性复制)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值