JS数组的深浅拷贝

javascript数组在使用时,时常会遇到数组备份的情况,之后对数组做些修改,再同原数组进行比对,查看数组的变化,这里就涉及到一个数组拷贝的问题。

浅拷贝只复制一层对象的属性;深拷贝递归复制了所有层级。


数组的拷贝,通常可以使用一个新的数组,指向现有数组

var arr = [el1, el2, el3...];
var arr2 = arr;

这种写法,待arr2做改变时,我们查看arr会同步做修改

ex 

var arr = ['liuche', 'zhouyafu', 'huoqubing', 'weiqing'];
var arr2 = arr;
arr2.push('liguang');
alert(arr); // 'liuche', 'zhouyafu', 'huoqubing', 'weiqing', 'liguang'
alert(arr2); // 'liuche', 'zhouyafu', 'huoqubing', 'weiqing', 'liguang'

这里我们看到,待修改数组arr2时,arr同时做了改变,这显然不是我们想要的结果。

示例中,这种直接将数组引用复制的方式就是浅拷贝。


那我们想要对数组进行备份的话,该如何操作呢,可以借助于Array对象的slice()方法和concat()方法。

slice方法

slice() 方法可从已有的数组中返回选定的元素。

arrayObject.slice(start,end)

其中:

start,必需。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置,从0开始。也就是说,-1 指最后一个元素,-2 指倒数第二个元素,以此类推。

end,可选。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。

slice方法返回一个新的数组,包含从 start 到 end (不包括该元素)的 arrayObject 中的元素。

若start为0,end 缺省,则相当于截取了整个数组的元素值,即我们这里要说的数组拷贝。

ex2

var arr = ['liuche', 'zhouyafu', 'huoqubing', 'weiqing'];
var arr2 = arr.slice(0);
arr2.push('liguang');
alert(arr); // 'liuche', 'zhouyafu', 'huoqubing', 'weiqing'
alert(arr2); // 'liuche', 'zhouyafu', 'huoqubing', 'weiqing', 'liguang'
但是,如果遇到多维数组,slice方法并不奏效

ex3

var arr = [['liuche', 'zhouyafu', 'weiqing'], ['chengajiao', 'weizifu', 'liupiao']];
var arr2 = arr.slice(0);
arr2.push('liguang');
alert(arr); // liuche,zhouyafu,weiqing,chengajiao,weizifu,liupiao
alert(arr2); // liuche,zhouyafu,weiqing,chengajiao,weizifu,liupiao,liguang

ex4

var arr = [['liuche', 'zhouyafu', 'weiqing'], ['chengajiao', 'weizifu', 'liupiao']];
var arr2 = arr.slice(0);
arr2[0][3] = 'liguang';
alert(arr); // liuche,zhouyafu,weiqing,liguang,chengajiao,weizifu,liupiao
alert(arr2); // liuche,zhouyafu,weiqing,liguang,chengajiao,weizifu,liupiao

上面两个示例中,ex3中,arr2修改后,arr并未跟着一起修改,因为arr2的修改,是给arr2新增了arr[3]元素;但是ex4中,arr2修改后,arr跟着一起修改了,原因在于arr中arr[0] 元素是个数组对象,并非单的数值。

concat方法

concat() 方法用于连接两个或多个数组。

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

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

其中

arrayX,必需。该参数可以是具体的值,也可以是数组对象。可以是任意多个。

concat方法返回一个新的数组。该数组是通过把所有 arrayX 参数添加到 arrayObject 中生成的。如果要进行 concat() 操作的参数是数组,那么添加的是数组中的元素,而不是数组。

使用concat() 方法时,若arrayX为空,则相当于原数组与一个空数组拼接,即返回原数组,做到原数组的拷贝。

那使用concat方法再来看看刚才的示例

ex5

var arr = [['liuche', 'zhouyafu', 'weiqing'], ['chengajiao', 'weizifu', 'liupiao']];
var arr2 = arr.concat();
arr2[0][3] = 'liguang';
alert(arr); // liuche,zhouyafu,weiqing,liguang,chengajiao,weizifu,liupiao
alert(arr2); // liuche,zhouyafu,weiqing,liguang,chengajiao,weizifu,liupiao
结果同ex4相同,并未得到我们想要的结果

实在无解之际,咨询了下一个专职做前端的同事,了解到一个万能的JS拷贝方法,无论是数组还是对象均可以实现深拷贝

JSON.parse(JSON.stringify(arr));
这个方法其实比较简单,先把所有的对象属性解析为简单数值,再将数值拼接解析为JS对象。

看之前的例子

ex6

var arr = [['liuche', 'zhouyafu', 'weiqing'], ['chengajiao', 'weizifu', 'liupiao']];
var arr2 = JSON.parse(JSON.stringify(arr));
arr2[0][3] = 'liguang';
alert(arr); // liuche,zhouyafu,weiqing,chengajiao,weizifu,liupiao
alert(arr2); // liuche,zhouyafu,weiqing,liguang,chengajiao,weizifu,liupiao

解决上面的问题。


经过上面的例子和分析,可以看出来,简单数组的拷贝可以通过slice方法和concat方法来实现,对于多维数组的实现,必须通过JSON.parse(JSON.stringify(obj))方法来实现。初次学习,有不当地方还望大家批评斧正。谢谢。






好的,关于JavaScript数组浅拷贝的问题,我可以为你做一个简要的介绍并举个例子。 首先来看浅拷贝,它会创建一个新的数组,这个新数组中的元素是对原始数组中对应元素的引用。这意味着如果修改原始数组中的元素,新数组中对应的元素也会受到影响。下面是一个浅拷贝的例子: ```javascript var originalArray = [1, 2, 3, 4]; var newArray = originalArray.slice(); originalArray[2] = 'changed'; console.log(originalArray); // [1, 2, "changed", 4] console.log(newArray); // [1, 2, 3, 4] ``` 上面代码中使用了 `slice()` 方法进行了拷贝操作。我们修改了原始数组中的第三个元素,发现新的数组并没有发生变化。 接下来再看深拷贝,它会创建一个新的数组,并且完全复制原始数组中的所有元素,这意味着即使修改原始数组中的元素,新数组中对应的元素也不会受到影响。由于JavaScript中没有原生的深拷贝方法,我们通常需要使用递归函数或第三方库来实现。下面是一个使用 JSON 序列化和反序列化实现深拷贝的例子: ```javascript var originalArray = [1, 2, [3, 4]]; var newArray = JSON.parse(JSON.stringify(originalArray)); originalArray[2][0] = 'changed'; console.log(originalArray); // [1, 2, ["changed", 4]] console.log(newArray); // [1, 2, [3, 4]] ``` 注意,使用 `JSON.stringify()` 和 `JSON.parse()` 实现深拷贝的时候,要确保原始数组仅包含可以被 JSON 序列化的数据类型,例如数字、字符串、布尔值、null 以及包含这些类型的数组和对象。如果原始数组中包含了函数、undefined、Symbol 等类型,这种方法就会出现问题了。 希望这个简单的例子能够帮助你理解 JavaScript数组浅拷贝的概念。如果你还有其他问题,请随时向我提出。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值