在认识深浅拷贝之前,我们需要对js的数据存储类型有一定的认识。前面文章讲到JavaScript
中存在两大数据类型:基本类型、引用类型。基本类型数据保存在在栈内存中,引用类型数据保存在堆内存中,引用数据类型的变量是一个指向堆内存中实际对象的引用,存在栈中
在对于数据存储类型有一定理解之后,我们才能对为什么有拷贝的概念和为什么又要有深浅拷贝的区分有更深的理解
对象的浅拷贝是其属性与拷贝源对象的属性共享相同引用(指向相同的底层值)的副本。因此,当你更改源或副本时,也可能导致其他对象也发生更改——也就是说,你可能会无意中对源或副本造成意料之外的更改。这种行为与深拷贝的行为形成对比,在深拷贝中,源和副本是完全独立的
对于浅拷贝,有选择地更改对象中现有元素的共享属性的值与给现有元素赋一个全新的值是不同的,理解这一点很重要
例如,如果在一个数组对象名为 copy
的浅拷贝中,copy[0]
元素的值是:{ "list":["butter","flour"] }
, 然后执行 copy[0].List = ["oil","flour"]
,那么源对象中的相应元素也将发生变化——因为你有选择地更改了源对象和浅拷贝共享的对象的属性
然而,如果你做的是 copy[0] = {"list":["oil","flour"]}
,那么源对象中的对应元素将不会改变——因为在这种情况下,你不仅仅是有选择地改变了浅拷贝与源对象共享的现有数组元素的属性;相反,你实际上是在浅拷贝中分配了一个全新的值给 copy[0]
数组元素
在 JavaScript 中,所有标准的内置对象复制操作 (展开语法、Array.prototype.concat()、Array.prototype.slice()、Array.from()、Object.assign() 和 Object.create())创建的是浅拷贝而不是深拷贝
示例代码如下:
- // 浅拷贝示例
- let originalArray = [1, 2, 3];
- let shallowCopyArray = originalArray; // 浅拷贝
-
- shallowCopyArray.push(4);
-
- console.log(originalArray); // [1, 2, 3, 4]
- console.log(shallowCopyArray); // [1, 2, 3, 4]
在上面的示例中,我们将原始数组originalArray
赋值给了shallowCopyArray
,这是一种浅拷贝方式。当我们修改shallowCopyArray
时,原始数组originalArray
也会被修改
对象的深拷贝是指其属性与其拷贝的源对象的属性不共享相同的引用(指向相同的底层值)的副本。因此,当你更改源或副本时,可以确保不会导致其他对象也发生更改;也就是说,你不会无意中对源或副本造成意料之外的更改。这种行为与浅拷贝的行为形成对比,在浅拷贝中,对源或副本的更改可能也会导致其他对象的更改(因为两个对象共享相同的引用)。
简单来说就是:深拷贝是指创建一个新的对象或数组,并且递归地复制原始对象或数组的所有值,而不仅仅是复制引用。这样,新对象或数组与原始对象或数组是完全独立的,彼此之间没有任何关联
如果一个 JavaScript 对象可以被序列化,则存在一种创建深拷贝将该对象转换为 JSON 字符串,然后使用 JSON.parse() 将该字符串转换回(全新的)JavaScript 对象:
示例代码如下:
- // 深拷贝示例
- let originalArray = [1, 2, 3]; 、
- let deepCopyArray = JSON.parse(JSON.stringify(originalArray)); // 深拷贝 deepCopyArray.push(4);
- console.log(originalArray); // [1, 2, 3]
- console.log(deepCopyArray); // [1, 2, 3, 4]
在上面的示例中,我们使用JSON.stringify()
将原始数组originalArray
转换为字符串,然后使用JSON.parse()
将字符串转换回数组,从而实现了深拷贝。当我们修改deepCopyArray
时,原始数组originalArray
不会受到影响
需要注意的是,深拷贝有一些限制。它无法复制函数、正则表达式、Date对象等特殊类型的数据。此外,如果原始对象或数组中存在循环引用,深拷贝也无法正常工作
在实际开发中,根据需求选择正确的拷贝方式非常重要。如果需要独立的副本并且不希望修改原始对象或数组,应使用深拷贝。如果只是需要引用原始对象或数组的副本,并且希望对其进行修改时,可以使用浅拷贝
前提为拷贝类型为引用类型的情况下:
浅拷贝是拷贝一层,属性为对象时,浅拷贝是复制,两个对象指向同一个地址
深拷贝是递归拷贝深层次,属性为对象时,深拷贝是新开栈,两个对象指向不同的地址