浅析Js中对象与数组的深拷贝

本文探讨了JavaScript中对象与数组深拷贝的常见误区,指出Object.assign()无法实现深拷贝,特别是在处理数组时。通过实例展示了slice()和concat()方法可以实现数组的深拷贝,但对象的深拷贝则需要其他策略,如JSON.parse()与JSON.stringify()结合使用,或者递归遍历复制。此外,还提到了循环遍历拷贝的方式,虽然直观但代码较多。
摘要由CSDN通过智能技术生成

一级属性深拷贝,形如这样的对象我们可以使用Object.assign()对其进行深拷贝。

let obj = {a:'123'}
let copy = Object.assign({},a) 
console.log(copy.a) //123
copy.a = '456'
console.log(obj.a) //123
console.log(copy.a) //456

这是对对象的一级属性进行深拷贝的常用方法,但是会有不少同学会忘记在Object.assign()上加上‘{}‘,写成这样:

let obj = {a:'123'}
let copy = Object.assign(a) 

这样写是实现不了深拷贝的,Object.assign()这个API的解释是这样的:Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

targersources
目标对象源对象

重点:他将返回目标对象

我们省略前面‘{}’就相当于这样把Object.assign(obj) 写成 Object.assign(obj,{})

Object.assign(obj,{})Object.assign({},obj)
返回对象obj{}

显然,改变Object.assign(obj,{})的值的时候就相当于改变obj原生对象,实现不了深拷贝。

另外对于数组来说,我们也理想当然的以为使用这个方法也能对数据进行深拷贝,对此我这能说,图样图新浦。

对于数组,我们这样尝试:

let arr = [{a:1}]
let arr2 = Object.assign({},arr)

下面我们打印看看arr2

console.log(JSON.stringify(arr2))
=>{"0":{"a":1}}

显然,数组使用Object.assign()进行深拷贝是不行的,他会把数组解析成可枚举的对象,形如:

[{a:1}]=>{0:{a:1}}

这样数据就变成了二级属性的对象,前面说过Object.assign()能够对一级属性进行深拷贝,但是对于形如这样的二级属性或者多级属性是不能够实现深拷贝的。

那么对于数组来说,我们可以怎么样实现深拷贝呢?这里我提供一个方法

let arr1 = [{a:1},{b:2}]
let arr2 = JSON.parse(JSON.stringify(arr1))
arr2[0].a = 11
console.log(arr1)
=>[{a:1},{b:2}]

同样这个方法对于对象也是可用的,不过这个方法存在一些弊端,具体在后面慢慢补充。

其实这个方法的原理就是先把数据或者对象转成字符串,字符串是存储在堆内存中的而且字符串的复制与修改对原始对象不产生影响的。具体情形是这样的:

JSON.stringify(arr1) => '[{a:1},{b:2}]' //字符串
JSON.parse( '[{a:1},{b:2}]') => [{a:1},{b:2}] //数组

另外,对于数组我们常用的方法还有通过循环遍历直接拷贝,如:

  let arr2 = []
for(let item of arr1){
   arr2.push(item)
}
arr2[0].a = 11
console.log(arr1) // [{a:1},{b:2}]
console.log(arr2) //[{a:11},{b:2}]

这种方式实现原理比较简单,不过代码量比起之前的方法多了很多。其实,总的来说返回一个新的数组就能实现数组的拷贝,其实js内置的几个AIP都能实现数组的深拷贝。

slice

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

参数描述
start必需。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1 指最后一个元素,-2 指倒数第二个元素,以此类推。
end可选。规定从何处结束选取。该参数是数组片断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素
var arr1 = ["1","2","3"];
var arr2 = arr1.slice(0);
arr2[1] = "0";
console.log(arr1); //["1","2","3"]
console.log(arr2);//["0","2","3"]

concat

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

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

var arr1 = ["1","2","3"];
var arr2 = arr1.concat();
arr2[1] = "0";
console.log(arr1); //["1","2","3"]
console.log(arr2);//["0","2","3"]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值