Jin's Blog
HOME WEEKLY ARCHIVE ABOUT RSS

JS 的深拷贝和浅拷贝总结

总结一下深复制和浅复制的区别,以及实现他们的方法。

浅复制和深复制的区别

对于基本类型(Undefined、Null、Boolean、Number 和 String),浅复制是对值的复制,对于引用类型来说,浅复制是对地址的复制,那么对于地址的复制又是什么意思呢?一段代码解释一下:

let arr1 = [1, 2, 3]
let arr2 = arr1
arr1.push(4)
console.log(arr1) // [1, 2, 3, 4]
console.log(arr2) // [1, 2, 3, 4]

// 只改变了 arr1,但是 arr2 也同时改变了。为什么呢?
// 因为 arr2 复制的仅仅是 arr1 的地址(指向数据的位置),所以 arr1 和 arr2 引用的是相同的数据
// 所以改变 arr1 的值时,arr2 也会发生改变

而深复制则是开辟新的栈,两个属性对应两个不同的地址,修改一个属性的数据,不会改变另一个属性数据。

浅复制

let obj = { a:1, arr: [2,3] };
let shallowObj = shallowCopy(obj);

function shallowCopy(src) {
let dst = {};
for (let prop in src) {
if (src.hasOwnProperty(prop)) {
dst[prop] = src[prop];
}
}
return dst;
}

obj.arr.push('4');
console.log(obj.arr) // [2, 3, "4"]
console.log(shallowObj.arr) // [2, 3, "4"]

// 明明只是修改了 obj 的 arr,但是 shallowObj 中的也被修改了。

原因:因为浅复制只会将对象的各个属性进行依次复制,并不会进行递归复制,而 JavaScript 存储对象都是存地址的,所以浅复制会导致 obj.arr 和 shallowObj.arr 指向同一块内存地址。

深复制

1. JSON实现

b = JSON.parse(JSON.stringify(a))

这个方法最方便,但是有它的局限性。

那么为什么不能复制函数呢?因为:JSON.stringify 函数将一个 JavaScript 对象转换成文本化的 JSON。不能被文本化的属性会被忽略。所以函数就被忽略调了。

2. 递归实现

// 递归深拷贝!
function clone(val) {
let newVal;
if (val instanceof Array) {
// 创建一个空的数组
newVal = [];
let i = val.length;
while (i--) {
newVal[i] = clone(val[i]);
}
return newVal;
} else if (typeof val === 'object') {
// 创建一个空对象
newVal = {};
for (let k in val) {
// 为这个对象添加新的属性
newVal[k] = clone(val[k]);
}
return newVal;
} else {
return val;
}
}

实现的原理

实现原理,先新建一个空对象,内存中新开辟一块地址,把被复制对象的所有可枚举的(注意可枚举的对象) 属性方法一一复制过来,注意要用递归(如果传入的变量是一个数组或者对象,那么就进行递归)来复制子对象里面的所有属性和方法,直到子子…..属性为基本数据类型。

总结,深拷贝需要理解两点:

  1. 新开辟内存地址
  2. 递归来刨根复制
PREVIOUS

JS 事件委托

NEXT

Vue 实现网易云音乐 WebApp

ALL TAGS