在ES6的系列文章中,基本都会提到Spread
——扩展运算符(...
)的使用。伴随着这个运算符的出现,也往往会牵扯出其他一些问题,深拷贝和浅拷贝就是其中之一。
相关背景
在讨论深拷贝和浅拷贝之前,我们先看一个例子:
let a = 'hi';b = a;b = 'hello';console.log(a);// 'hi'let arr1 = [1,2,3];arr2 = arr1;arr2[0] = 0;console.log(arr1);// [0,2,3]
可以看到:为不同的js变量复制值时,结果是不同的。把字符串a
的值复制给b
,改变b
的值不会影响a
的值,而把数组arr1
的值复制给arr2
时,改变arr2
的值,arr1
的值也跟着改变了。
这是因为js存在两种不同数据类型的值:基本类型值
和引用类型值
。
在访问这两种类型的变量时,其访问方式是不同的。在这里,先记一下结论:
- 基本数据类型是按值访问的
- 引用数据类型是按引用访问的
(实际上这种说法并不严密,为便于理解,我们先这么记)
什么意思?
JavaScript不允许直接访问内存中的位置,换句话说,不能直接操作对象的内存空间。
因此,在操作对象时,我们实际上是在操作对象的引用,而不是实际的对象。
从一个变量向另一个变量复制值时(不管是复制基本类型还是引用类型),都会先为这个新变量分配一个空间,然后把该值复制到新创建的这个空间里。
不同的是,在复制引用类型的值时,实际上复制过去的是一个指针,示例图如下:
在js中,除了7种基本类型外,其他的都是引用类型,比如Object
,Array
,Function
,所以不难理解:
let obj1 = {name:'hx',age:18};let obj2 = obj1;obj2.age = 0;console.log(obj1);// {name:'hx',age:0}