「Learning」深拷贝与浅拷贝

原文地址:低门槛彻底理解JavaScript中的深拷贝和浅拷贝

基本类型 引用类型
保存位置 保存在栈内存中 保存在堆内存中
保存方式 完全保存在内存中的一个位置 变量保存的是一个指针,
指针指向内存中的一个位置
数据 简单数据段 对象
具体类型 Boolean, Null, Undefined, Number, String, Symbol Object, Array, Function

基本类型和引用类型

  • ECMAScript变量包含基本类型和引用类型两种数据类型
  • 基本类型
    • 保存在栈内存中 => 完全保存在内存中的一个位置
    • 简单数据段
    • Boolean, Null, Undefined, Number, String, Symbol
  • 引用类型
    • 保存在堆内存中 => 变量保存的是一个指针,指针指向内存中的一个位置
    • 对象
    • Object, Array, Function

深拷贝与浅拷贝的概念只存在于引用类型。

浅拷贝就是只拷贝了指针,即A浅拷贝了B,实际上A和B指向同一个内存空间。

深拷贝是拷贝了原对象的所有内容,同时将这些内容放置到另一个内存空间里。此时,如果原对象被删除了,不会影响到新对象。

image-20180814153715007

深拷贝和浅拷贝

一维数据类型

  • Array
    • arr2 = arr1.slice()
    • arr2 = arr1.concat([])
    • arr2 = Array.from(arr1)
  • Object
    • obj2 = Object.assign({}, obj1)
    • obj2 = JSON.parse(JSON.stringify(obj1))
      • 无法处理undefined,symbolfunction,会被转为null

二维及以上数据类型

  • 递归
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
function deepCopy(obj, parent = null) {
2. // 创建一个新对象
3. let result = {};
4. let keys = Object.keys(obj),
5. key = null,
6. temp= null,
7. _parent = parent;
8. // 该字段有父级则需要追溯该字段的父级
9. while (_parent) {
10. // 如果该字段引用了它的父级则为循环引用
11. if (_parent.originalParent === obj) {
12. // 循环引用直接返回同级的新对象
13. return _parent.currentParent;
14. }
15. _parent = _parent.parent;
16. }
17. for (let i = 0; i < keys.length; i++) {
18. key = keys[i];
19. temp= obj[key];
20. // 如果字段的值也是一个对象
21. if (temp && typeof temp=== 'object') {
22. // 递归执行深拷贝 将同级的待拷贝对象与新对象传递给 parent 方便追溯循环引用
23. result[key] = DeepCopy(temp, {
24. originalParent: obj,
25. currentParent: result,
26. parent: parent
27. });
28. } else {
29. result[key] = temp;
30. }
31. }
32. return result;
33.}
34.var obj1 = {
35. x: 1,
36. y: 2
37.};
38.obj1.z = obj1;
39.var obj2 = deepCopy(obj1);
40.console.log(obj1);
41.console.log(obj2);