javascript数组、对象的复制方法

  我们在JS程序中需要进行频繁的变量赋值运算,对于字符串、布尔值等可直接使用赋值运算符 “=” 即可,但是对于数组、对象、对象数组的拷贝,我们需要理解更多的内容。

  首先,我们需要了解JS的浅拷贝与深拷贝的区别。

  我们先给出一个数组:

var arr = ["a","b"];

  现在怎么创建一份arr数组的拷贝呢?直接执行赋值运算吗?我们来看看输出结果:

var arrCopy = arr;
arrCopy[1] = "c";
arr   // => ["a","c"]

  可以发现对拷贝数组 arrCopy 进行操作时原数组也相应地被改变了,这就是JS的浅拷贝模式(或者说不是真正的复制)。所以我们可以指出对数组、对象、对象数组进行简单赋值运算只是创建了一份原内容的引用,指向的仍然是同一块内存区域,修改时会对应修改原内容,而有时候我们并不需要这种模式,这就需要对内容进行复制。

一.数组的复制

  条条大道通罗马,实现数组的复制,是有好几种方法的。

1.for循环实现数组的复制

  for循环是非常好用的。如果不知道高级方法,通过for循环能够完成我们大多数的需求。

var arr = [1,2,3,4,5];
var arr2 = copyArr(arr);

function copyArr(arr) {
    let res = []
    for (let i = 0; i < arr.length; i++) {
        res.push(arr[i])
    }
    return res
}

  或者

var arr = ["a", "b"], arrCopy = [];
for (var item in arr) arrCopy[item] = arr[item];
arrCopy[1] = "c";
arr   // => ["a", "b"]
arrCopy   // => ["a", "c"]

  对于上面两种,如果是多维数据,就需要递归处理,即考虑伪多维数组可以写成函数形式:

function arrDeepCopy(source){
    var sourceCopy = [];
    for (var item in source) sourceCopy[item] = typeof source[item] === 'object' ? arrDeepCopy(source[item]) : source[item];
    return sourceCopy;
}

  这种方法简单粗暴,但是利用JS本身的函数我们可以更加便捷地实现这个操作。

2.slice方法实现数组的复制

  slice() 方法可从已有的数组中返回选定的元素。调用格式为:

arrayObject.slice(start,end)

  方法返回一个新的数组,包含从 start 到 end (不包括该元素)的 arrayObject 中的元素。该方法并不会修改数组,而是返回一个子数组。

  在这里我们的思路是直接从数组开头截到尾:

var arr = [1,2,3,4,5]
var arr2 = arr.slice(0)
arr[2] = 5
console.log(arr)
console.log(arr2)

  可以看出成功创建了一份原数组的拷贝。

3.concat方法实现数组的复制

  concat() 方法用于连接两个或多个数组。调用格式为:

arrayObject.concat(arrayX,arrayX,......,arrayX)

  该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。使用这种方法的思路是我们用原数组去拼接一个空内容,返回的便是这个数组的拷贝:

var arr = [1,2,3,4,5]
var arr2 = arr.concat()
arr[2] = 5
console.log(arr)
console.log(arr2)

4.ES6扩展运算符实现数组的复制

  以上之前讲的方法全部过时了,用下面的方法实现数组的复制是最简单的。

var arr = [1,2,3,4,5]
var [ ...arr2 ] = arr
arr[2] = 5
console.log(arr)
console.log(arr2)

 

二.对象的复制

1.万能的for循环实现对象的复制
  在很多时候,for循环能够解决大问题,我们可以自己命名一个函数进行这一操作:

var objDeepCopy = function(source){
    var sourceCopy = {};
    for (var item in source) sourceCopy[item] = source[item];
    return sourceCopy;
}

  但是对于复杂结构的对象我们发现这个函数并不适用,例如:

var obj = { "a": { "a1": ["a11", "a12"], "a2": 1 }, "b": 2 };

  所以需要进行一点修改:

var objDeepCopy = function(source){
    var sourceCopy = {};
    for (var item in source) sourceCopy[item] = typeof source[item] === 'object' ? objDeepCopy(source[item]) : source[item];
    return sourceCopy;
}
var objCopy = objDeepCopy(obj);
objCopy.a.a1[1] = "a13";
obj   // => { "a": { "a1": ["a11", "a12"], "a2": 1 }, "b": 2 }
objCopy   // => { "a": { "a1": ["a11", "a13"], "a2": 1 }, "b": 2 }

  如果再考虑更奇葩更复杂的情况,例如我们定义:

var obj = [{ "a": { "a1": ["a11", "a12"], "a2": 1 }, "b": 2 }, ["c", { "d": 4, "e": 5 }]];

  这是一个由对象、数组杂合成的奇葩数组,虽然我们平时写程序基本不可能这么折腾自己,但是可以作为一种特殊情况来考虑,这样我们就可以结合之前说的方法去拓展拷贝函数:

var objDeepCopy = function (source) {
    var sourceCopy = source instanceof Array ? [] : {};
    for (var item in source) {
        sourceCopy[item] = typeof source[item] === 'object' ? objDeepCopy(source[item]) : source[item];
    }
    return sourceCopy;
}
var objCopy = objDeepCopy(obj);
objCopy[0].a.a1[1] = "a13";
objCopy[1][1].e = "6";
obj   // => [{ "a": { "a1": ["a11", "a12"], "a2": 1 }, "b": 2 }, ["c", { "d": 4, "e": 5 }]]
objCopy   // => [{ "a": { "a1": ["a11", "a13"], "a2": 1 }, "b": 2 }, ["c", { "d": 4, "e": 6 }]]

  这样它就可以作为一个通用函数替我们进行复制操作了。

2.转换成json再转换成对象实现对象的复制

  上面的代码实在是比较长,所以,用一个更暴力的方法吧!代码如下:

var obj = {
  name: 'FungLeo',
  sex: 'man',
  old: '18'
}
var obj2 = JSON.parse(JSON.stringify(obj))

  这个原理没什么好解释的,实在是够简单粗暴的啦!

3.扩展运算符实现对象的复制

var obj = {
  name: 'FungLeo',
  sex: 'man',
  old: '18'
}
var { ...obj2 } = obj
obj.old = '22'
console.log(obj)
console.log(obj2)

 

PS:一个数组去重的方法

function dedupe(array) {
  return [...new Set(array)]
}
var arr = [1,2,2,3,3,4,4,5,5]
console.log(dedupe(arr))

 

参考文章:https://blog.csdn.net/fungleo/article/details/54931379

https://www.cnblogs.com/jiangzilong/p/6513552.html

posted on 2018-12-19 15:25  bijian1013  阅读(695)  评论(0编辑  收藏  举报

导航