深拷贝与浅拷贝
对于基本类型的数据,深拷贝与浅拷贝都相同,都是开辟一块新的空间,将数组赋值存入。旧值的改变不会影响新值,然鹅对于引用类型的数据就不相同了。
浅拷贝
对于引用类型的数据实行浅拷贝,当旧值发生改变时,新值也会改变,这是因为浅拷贝仅仅只是在栈中新开辟一块空间,将旧值存在栈中的指针复制给新值,新旧值指向的是同一块内存。旧值改变时,新值自然也是改变了的。
var a = [1]; var b = a; a[0] = 2; console.log(b); // [2]
实现浅拷贝的方式
Object.assign
展开运算符
只能实现简单数据类型的深拷贝
var a = {name:'ashen'} var b = {...a}
深拷贝
而在新拷贝中,对于引用类型的拷贝是在堆中新开辟一块空间,将旧的数值复制该这个空间,再在栈中开辟一块空间指向堆中这个地址。新旧值已不再相互影响.
实现深拷贝的几种方式
使用JSON方式
var a = [1, 2, 3]; var b = JSON.parse(JSON.stringify(a)); a[1] = 1; console.log(b); // [1, 2, 3]
缺点:
- 不能实现其中函数的拷贝
- 无法拷贝原型链上的属性和方法
- 数据层次很深时,会栈溢出
使用递归
function deepClone(obj) { var newObj = Array.isArray(obj) ? [] : {}; for (var key in obj) { if (obj[key] instanceof Object) { newObj[key] = deepClone(obj[key]) }else{ newObj[key] = obj[key] } } return newObj; } var a = [{name:'ashen', age: 21}, 1] var b = deepClone(a); console.log(b)
使用数组的forEach实现
function deepClone(obj) { var copy = Object.create(Object.getPrototypeOf(obj)); var propnames = Object.getOwnPropertyNames(obj); propnames.forEach(items => { let item = Object.getOwnPropertyDescriptor(obj, items); Object.defineProperty(copy, items, item) }) return copy; } var a = [{name:'ashen', age: 21}, 1] var b = deepClone(a); console.log(b)
注意点:
数组的slice()方法并不能实现深拷贝
var a = [1, [1, 2], 3]; var b = a.slice();
a[0] = 2;
console.log(b); // [1, [1, 2], 3]
a[1][1] = 1; console.log(b); // [1, [1, 1], 3]