前言
- 在谈论浅拷贝和深拷贝之前,先复习一下JS数据类型在赋值方面的知识。
- 基本数据类型(值类型):基本数据类型的变量和值都是存放在栈内存中,声明之后会分配一块内存区域,基本数据类型之间的赋值是直接把栈内存中存的值赋值给变量(传值)。也就是说两个变量只是占用的空间大小相同,值相同,但是存储的位置不同。(可以理解为重新开辟了一个新的内存空间) 因此,当其中一个值改变的时候,不会对另一个值有影响。
-
// 案例如下 var a=10; var b=a; - 引用类型(对象类型):对于引用类型,变量依然保存在栈内存中。而值是保存在堆内存中,当一个变量指向另一个变量时,它们其实指向的是同一个内存空间,因为变量保存的是指向实际对象的指针。从一个变量向另一个变量复制引用类型的值,复制的其实是指针地址而已,因此两个变量最终都指向同一个对象。
- 如图:
浅拷贝和深拷贝
- 首先,浅拷贝和神拷贝指的是对象类型之间的赋值操作,基本数据类型之间的赋值某种程度上就是一种深拷贝。
- 两者之间的区别:浅拷贝就是只拷贝了对象在堆内存中的地址,但实际a,b两者指向的是同一块内存空间。而深拷贝则是在堆内存中开辟了一块新空间,但里面存放的内容是一样的,这样改变其中一个对象的值就不会影响到另一个对象了。
- 一般情况下,对象的等号赋值,函数的传参,都是浅拷贝,也就是只拷贝了数据的地址。
如何实现深拷贝?
1. 利用JS中对JSON的解析方法
* 什么是JSON?
JSON( JavaScript Object Notation) 是一种轻量级的存储和传输数据的格式。经常在数据从服务器发送到网页时使用。
* JSON的两个方法:
1. JSON.stringify(value) 方法用于将 JavaScript 值转换为 JSON 字符串,并返回该字符串。
2. JSON.parse(value) 用于将一个 JSON 字符串转换为对象 并返回该对象。
* 注意:这两个方法都是会返回一个新的字符串或者对象。
* 例子:
```javascript
var a = {
name: "ken",
age: 18
}
var b = a;
console.log(a === b); // true 直接赋值操作,典型的浅拷贝。
------------------------------------------------------
var a = {
name: "ken",
age: 18
}
var b = JSON.parse(JSON.stringify(a)); // 先将a转换为字符串,再转换回对象。
console.log(a === b); // false 此时两个指向的不是同一个对象,所以为false,达到了深拷贝目的。
```
* 缺陷:受json数据的限制,无法拷贝函数,undefined,NaN属性。
2. 函数递归方式
//代码分析: 形参obj 代表被拷贝目标, 调用函数 传入拷贝目标,
// 通过Array.isArray(obj)判断obj的类型,result根据obj类型定义自身是数组还是对象。
// 通过 for in 遍历拷贝目标,
// 使用 typeof 判断其每一个元素或者属性, 是否为obj类型(typeof Array/Object 返回值皆为object)
// 若该属性/元素, 部位null 并且 typeof返回值为object, 则代表其为复杂数据类型, 递归调用 deepCopy(obj[key]),继续拷贝其内部
// 否则: 代表该元素非 数组 非对象, 为基本数据类型/函数 等 , 直接赋值拷贝即可
// 最后返回拷贝完成的result ,函数执行完毕
function deepCopy(obj) {
var result = Array.isArray(obj) ? [] : {};
for (var key in obj) {
if (typeof obj[key] === 'object' && obj[key] !== null) {
result[key] = deepCopy(obj[key]); //递归复制
} else {
result[key] = obj[key];
}
}
return result;
}
3. 使用函数库lodash中的cloneDeep()方法
cloneDeep 作用是将变量数据中所有的值,都依次拷贝一份新的出来,包括但不限于 arrays,array buffers ,booleans, Date, maps, numbers,Object,regexes,sets,strings,symbols,typed arrays。注意只会拷贝对象的可枚举属性。如果对象不可拷贝,比如是 Error、Function、DOM、WeakMap,那么返回空对象。