深浅拷贝
1. 浅拷贝
js的数据类型,分为基本类型和引用类型
js基本类型:Number、String、Boolean, 其传值方式是按照按值传递的方式
var num1 = 1;
var num2 = num1;
num2 = 2;
此时的num1的值不受影响,仍为1;
引用类型是按引用传值
var obj1 = { a: 10, b: 20, c: 30 };
var obj2 = obj1;
obj2.b = 100;
console.log(obj1);
// { a: 10, b: 100, c: 30 } <-- b 被改到了
console.log(obj2);
// { a: 10, b: 100, c: 30 }
上面赋值,是引用赋值,是将 obj1 的地址复制给 obj2, obj1 和 obj2 指向的是同一个内存区域。因此对任何一个修改,其实修改的都是同一个对象,这就是所谓的浅拷贝。
浅拷贝的几种方式
-
Object.assign()
可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。
-
lodash的clone方法
-
...操作符
let obj1 = { name: 'Kobe', address:{x:100,y:100}} let obj2= {... obj1} obj1.address.x = 200; obj1.name = 'wade' console.log('obj2',obj2) // obj2 { name: 'Kobe', address: { x: 200, y: 100 } }
-
Array.prototype.concat
let arr = [1,2,3]; let arr2 = [4,5,6];let arr3 = arr.concat(arr2)
let arr = [1, 3, { username: 'kobe' }]; let arr2 = arr.concat(); arr2[2].username = 'wade'; console.log(arr);
-
Array.prototype.slice
let arr = [1, 3, { username: ' kobe' }]; let arr3 = arr.slice(); arr3[2].username = 'wade' console.log(arr); // [ 1, 3, { username: 'wade' } ]
2. 深拷贝
深拷贝会另外创造一个一模一样的对象,新旧对象不共享内存,因此修改其中的一个对象不会改到另一个对象。
深拷贝的几种方式
1. 手动复制
obj1 = {a:1,b:2}
obj2 = {a: obj1.a,b: obj.b}
2. JSON.parse(JSON.stringify())
用JSON.stringify转为字符串 再用JSON.parse把字符串再转为新的对象
可以处理数组和对象的深拷贝,但是不能处理函数和正则,因为这两者基于这两个函数处理后得到的结果不再是正则/函数
缺点:
- 会忽略undefined
- 会忽略symbol
- 不能序列化函数
- 不能解决循环引用的对象
4. 递归拷贝
递归深拷贝的实现:
var deepCopy = function(obj) {
if (typeof obj !== 'object') return
var newObj = obj instanceof Array ? [] : {}
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key]
}
}
return newObj
}
缺点: 相互引用会出现死循环,深拷贝的做法是遇到对象就进行递归 复制,那么结果只能无限循环下去
5. object.create()方法
Object.create()方法创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。
也就是说,现有对象是新的对象的构造函数的prototype.其实现过程如下:
function create(obj) {
function F() {}
F.prototype = obj
return new F()
}
6. 直接使用一些库函数方法, 如lodash
var _ = require('lodash')
_.cloneDeep()