1.用 JSON.stringify 把对象转换成字符串,再用 JSON.parse 把字符串转换成新的对象
var targetObj = JSON.parse(JSON.stringify(copyObj))
let arr4 = JSON.parse(JSON.stringify(arr))
但是需要注意的是
(1)如果对象里有函数,函数无法被拷贝下来
(2)无法拷贝copyObj对象原型链上的属性和方法
(3)当数据的层次很深,会栈溢出,比如复杂的树形结构
2.Object.assign()拷贝
当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝, Object.assign()拷贝的是属性值。假如源对象的属性值是一个对象的引用,那么它也只指向那个引用。
var obj1 = {a: 1, b: 2}
var obj2 = {A: 1, B: 2}
var Coll = Object.assign({},obj1,obj2)
obj1.a = '被修改了'
Coll // {a: 1, b: 2, A: 1, B: 2}
修改obj1.a 的属性不会影响Coll,是因为 obj.a 对应的 数字1是 基本类型,按值引用。如果obj1.a 对应引用类型的值,复制的就是这个引用类型的地址。
var obj1 = {a: {name: '小红'}, b: 2}
var obj2 = {A: 1, B: 2}
var Coll = Object.assign({},obj1,obj2)
obj1.a.name = '被修改了'
Coll //{"a":{"name":"被修改了"},"b":2,"A":1,"B":2}
3使用递归的方式实现深拷贝
var obj1 = {a: {name: '小红'}, b: 2, arr:[1,2]}
var obj2 = {}
//参数:初始值,完成值
function deepClone(initalObj, finalObj) {
var obj = finalObj || {};
for (var i in initalObj) {
//判断是否引用类型,object,Array 的typeof检测 都是object
if (typeof initalObj[i] === 'object') {
//递归前,判断是对象还是数字,初始化
obj[i] = (initalObj[i].constructor === Array) ? [] : {};
//递归自己
arguments.callee(initalObj[i], obj[i]);
} else {
//基础类型值 直接复制
obj[i] = initalObj[i];
}
}
return obj;
}
deepClone(obj1, obj2)
console.log(obj2) //{a: {name: '小红'}, b: 2, arr:[1,2]}
原理: 在浅拷贝部分的原理是一样的,如果第一层键名/下标 对应的是基础类型的值,就直接复制, 如果是引用类型的值,采用递归的方式,进入到这个引用类型的值。到了第二层,循环操作第一层的步骤。
注意: arguments.callee() 这个方法因为性能问题,在es5严格模式下禁止使用,具体原因。 解决方法很简单,直接用函数名即可。
另外如果遇到两个相互引用的对象,会出现死循环的情况
为了避免相互引用的对象导致死循环的情况,则应该在遍历的时候判断是否相互引用对象,如果是则退出循环。
改进版代码,如下:
function deepClone(initalObj, finalObj) {
var obj = finalObj || {};
for (var i in initalObj) {
var prop = initalObj[i]; // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
if(prop === obj) {
continue;
}
if (typeof prop === 'object') {
obj[i] = (prop.constructor === Array) ? [] : {};
arguments.callee(prop, obj[i]);
} else {
obj[i] = prop;
}
}
return obj;
}
3.jquery的$.extend
$.extend(true, obj1, obj2)
如果需要用深拷贝,第一个参数为true即可。不用则可以省略true。
var $ = require('jquery');
var obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
var obj2 = $.extend(true, {}, obj1);
obj1.b.f === obj2.b.f; // false
4.最后一种我觉得最简单的也是比较常用的
lodash.cloneDeep()实现深拷贝。