JavaScript浅拷贝和深拷贝

最近发现学点什么零碎知识点都给记在博客上记得挺牢的,所以比较高产:)

直接赋值

今天讲讲JavaScript的浅拷贝和深拷贝,不少面试题爱考这个。首先当我们要复制一个数组时,可能会采取直接赋值的方式,像这样:

1
2
3
4
5
var arr1=[1,2,3];
var arr2=arr1;
arr2[1]=7;
console.log(arr1);//[1, 7, 3]
console.log(arr2);//[1, 7, 3]

这就出事了,一个数组改变另一个数组也会跟着变,这就是浅拷贝。

我们可以通过slice、concat方法来实现深拷贝

slice()

先从网上摘一段方法介绍

对于array对象的slice函数,返回一个数组的一段。(仍为数组)
arrayObj.slice(start, [end])
参数:
arrayObj 必选项。一个 Array 对象。
start 必选项。arrayObj 中所指定的部分的开始元素是从零开始计算的下标。
end可选项。arrayObj 中所指定的部分的结束元素是从零开始计算的下标。
说明:
slice 方法返回一个 Array 对象,其中包含了 arrayObj 的指定部分。
slice 方法一直复制到 end 所指定的元素,但是不包括该元素。
如果 start 为负,将它作为 length + start处理,此处 length 为数组的长度。
如果 end 为负,就将它作为 length + end 处理,此处 length 为数组的长度。
如果省略 end ,那么 slice 方法将一直复制到 arrayObj 的结尾。
如果 end 出现在 start 之前,不复制任何元素到新数组中。

好,我们来试试slice方法:

1
2
3
4
5
var arr1=[1,2,3];
var arr2=arr1.slice();
arr2[1]=9;
console.log(arr1);//[1, 2, 3]
console.log(arr2);//[1, 9, 3]

concat()

是不是就没问题了?再来看看concat方法:

concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。
语法:arrayObject.concat(arrayX,arrayX,……,arrayX)
说明:返回一个新的数组。该数组是通过把所有 arrayX 参数添加到 arrayObject 中生成的。如果要进行 concat() 操作的参数是数组,那么添加的是数组中的元素,而不是数组。

1
2
3
4
5
var arr1 = ["1","2","3"];
var arr2 = arr1.concat();
arr2[1] = "9";
console.log(arr1);//[1, 2, 3]
console.log(arr2);//[1, 9, 3]

局限性

目前看来,这两个方法做深拷贝没什么问题,但它们也存在着局限性。只适用于不包含引用对象的一维数组的深拷贝

对象的深拷贝

既然如此,那该怎么对对象进行深拷贝呢?其实也很简单,把对象的属性都给遍历一次,再赋给一个新的对象就行。举个例子:

1
2
3
4
5
6
7
var a ={name:'Jack',age:40};
var b =new Object();
b.name=a.name;
b.age=a.age;
a.name='robin';
console.log(a);//{name: "robin", age: 40}
console.log(b);//{name: "Jack", age: 40}

————2018.10.17更新————-

拓展运算符

这是ES6带来的新特性,虽然ES6出来很久了,但因为公司的一些历史遗留问题,未能随心所欲地使用。到了18年,开始开发小程序,旧项目上了babel,已经没有了障碍,所以写一下这个能省下不少代码的特性。

数组深拷贝

1
2
3
4
5
let a = [1,2,3,4];
let b = [...a];
b[1] = 5;
console.log(a) => [1, 2, 3, 4]
console.log(b) => [1, 5, 3, 4]

对象深拷贝

1
2
3
4
5
let a = {"name":"jack","age":12};
let b = {...a};
b.name = "leo";
console.log(a) => {name: "jack", age: 12}
console.log(b) => {name: "leo", age: 12}

结语

技术的积累是一点一滴的,正所谓温故而知新,像本篇这种总结基础知识点的文章,偶尔翻来看一看感觉也不错~:)