JavaScript数组复制详解:浅拷贝与深拷贝实现

作者:异步漫步时间:2026-10-26 12:52:46浏览:381

本文详细解析JavaScript中数组复制的两种主要方式:浅拷贝与深拷贝。通过concat、slice、扩展运算符及Object.assign实现浅拷贝,并探讨JSON.parse、递归函数及lodash库在深拷贝中的应用,重点分析各方法的局限性与适用场景。

在JavaScript开发中,数组复制是常见需求。由于Array属于引用类型,若仅通过arrA=arrB进行简单赋值,并未创建新数组,而是让两个变量指向同一内存地址。此时修改任一变量,另一个也会随之改变,这通常不符合预期结果。

  var arr = [1, 2, 3];
  var newArr = arr;
  arr.push(4);
  console.log(newArr1);  // [1, 2, 3, 4]

接下来介绍数组的浅复制方法。

这种方法适用于结构简单的数组,即数组内部不包含嵌套对象或嵌套数组的情况。

方法一:使用concat()。

  • concat()函数用于连接两个或多个数组。
  • 该函数不会修改现有数组,而是返回一个新数组,其中包含被连接数组的值。
  var arr = [1, 2, 3];
  var newArr = arr.concat();
  arr.push(4);
  console.log(newArr); // [1, 2, 3]

方法二:使用slice()。

  • slice()函数返回一个新数组,包含从原数组中选定的元素。
  • 该函数从指定的start参数开始选取元素,并在给定的end参数处结束(不包含end位置的元素)。
  • slice()函数同样不会改变原始数组。
  var arr = [1, 2, 3];
  var newArr = arr.slice();
  arr[0] = 10;
  console.log(arr);// [10, 2, 3]
  console.log(newArr);// [1, 2, 3]

方法三:使用扩展运算符。

  var arr = [1, 2, 3];
  var [ ...newArr ] = arr;
  arr[0] = 10;
  console.log(arr); // [10, 2, 3]
  console.log(newArr);// [1, 2, 3]

方法四:使用Object.assign()。

 var arr = [1, 2, 3];
 var newArr = Object.assign([], arr);
 arr[0] = 10;
 console.log(arr);// [10, 2, 3]
 console.log(newArr);// [1, 2, 3]

需要注意的是,如果数组元素包含对象或数组,上述四种浅拷贝方法仅会拷贝引用。因此,修改其中一个数组的元素,另一个数组的对应元素也会发生变化。

例如:

  var arr = [ { a: 1 }, [ 1, 2 ], 3 ];
  let newArr = arr.concat();
  arr[0].a = 2;
  console.log(arr); // [ { a: 2 }, [ 1, 2 ], 3 ]
  console.log(newArr);// [ { a: 2 }, [ 1, 2 ], 3 ] 值被影响

接下来介绍深复制方法。

深复制可以完全拷贝数组,即使内部嵌套了对象或数组,新旧数组之间也不会相互影响。

方法一:使用JSON.parse(JSON.stringify(arr))。

  var arr = [ { a: 1 }, [ 1, 2 ], 3 ];
  // let newArr = JSON.parse(JSON.stringify(arr));
  let newArr = arr.concat();
  arr[0].a = 2;
  console.log(arr); // [ { a: 2 }, [ 1, 2 ], 3 ]
  console.log(newArr);// [ { a: 1 }, [ 1, 2 ], 3 ]

然而,该方法存在明显的局限性。

  • 它会忽略undefined类型的值。
  • 它也会忽略symbol类型的值。
  • 该方法无法序列化函数。
  • 此外,它不能处理包含循环引用的对象。

下面通过一个示例说明:

let a = {
  age: undefined,
  sex: Symbol('male'),
  jobs: function() {},
  name: 'sun'
}
let b = JSON.parse(JSON.stringify(a))
console.log(b) // {name: "sun"}

方法二:通用深拷贝方法(适用于数组或对象)。

在拷贝过程中判断属性值的类型,若为对象,则继续递归调用深拷贝函数(此为简易版实现)。

  var deepCopy = function(obj) {
    // 判断是否是对象
    if (typeof obj !== 'object') return;
    // 判断obj类型,根据类型新建一个对象或者数组
    var newObj = obj instanceof Array ? [] : {}
    // 遍历对象,进行赋值
    for (var key in obj) {
      if (obj.hasOwnProperty(key)) {
        let val = obj[key];
        // 判断属性值的类型,如果是对象,递归调用deepCopy
        newObj[key] = typeof val === 'object' ? deepCopy(val) : val
      }
    }
    return newObj
  }

方法三:利用lodash库提供的深拷贝函数。

_.cloneDeep(value)

其中value参数即为需要深拷贝的值。

简单使用示例如下:

var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false

在Vue项目中的使用方式。

首先进行安装。

npm i --save lodash

然后在main.js文件中引入。

import _ from 'lodash';
Vue.prototype._ = _;

最后在实际代码中使用。

let newObj = this._.cloneDeep(oldObj)

总结。

以上内容为个人经验分享,旨在提供参考,欢迎大家支持本站。

作者最新文章