JS中深拷贝数组、对象、对象数组方法(转载)

 

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

首先,咱们须要了解JS的浅拷贝与深拷贝的区别。函数

咱们先给出一个数组:测试

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

如今怎么建立一份arr数组的拷贝呢?直接执行赋值运算吗?咱们来看看输出结果spa

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

能够发现对拷贝数组 arrCopy 进行操做时原数组也相应地被改变了,这就是JS的浅拷贝模式。因此咱们能够指出对数组、对象、对象数组进行简单赋值运算只是建立了一份原内容的引用,指向的仍然是同一块内存区域,修改时会对应修改原内容,而有时候咱们并不须要这种模式,这就须要对内容进行深拷贝。code

1 数组的深拷贝


 对于数组的深拷贝常规的有三种方法:对象

方法一:遍历复制

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

考虑伪多维数组能够写成函数形式:blog

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

这种方法简单粗暴,可是利用JS自己的函数咱们能够更加便捷地实现这个操做。内存

方法二:slice()

能够参考 W3School 对 slice() 方法的描述:slice() 方法可从已有的数组中返回选定的元素。字符串

调用格式为:it

arrayObject.slice(start,end)

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

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

arrCopy = arr.slice(0);
arrCopy[1] = "c";
arr      // => ["a", "b"] 
arrCopy   // => ["a", "c"]

能够看出成功建立了一份原数组的拷贝。

方法三:concat()

能够参考 W3School 对 concat() 方法的描述:concat() 方法用于链接两个或多个数组。

调用格式为:

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

该方法不会改变现有的数组,而仅仅会返回被链接数组的一个副本。

使用这种方法的思路是咱们用原数组去拼接一个空内容,放回的即是这个数组的拷贝:

arrCopy = arr.concat();
arrCopy[1] = "c";
arr      // => ["a", "b"] 
arrCopy   // => ["a", "c"]

二、对象的深拷贝


 对于数组的深拷贝咱们有了概念,那么通常对象呢?

咱们给出一个对象:

var obj = { "a": 1, "b": 2 };

一样作测试:

var objCopy = obj;
objCopy.b = 3;
obj      // => { "a": 1, "b": 3 }
objCopy   // => { "a": 1, "b": 3 

一样,简单的赋值运算只是建立了一份浅拷贝。

而对于对象的深拷贝,没有内置方法可使用,咱们能够本身命名一个函数进行这一操做:

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 }]]

这样它就能够做为一个通用函数替咱们进行深拷贝操做了。

相关文章
相关标签/搜索