一级属性深拷贝,形如这样的对象我们可以使用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() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
targer | sources |
---|---|
目标对象 | 源对象 |
重点:他将返回目标对象
我们省略前面‘{}’就相当于这样把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"]