一、 JSON.stringify()以及JSON.parse()
var obj1 = { x: 1, y: 2, z: 3 }
var str = JSON.stringify(obj1);
var obj2 = JSON.parse(str);
缺点:
- 会忽略 undefined和symbol;
- 不可以对Function进行拷贝,因为JSON格式字符串不支持Function,在序列化的时候会自动删除;
- 诸如 Map, Set, RegExp, Date, ArrayBuffer 和其他内置类型在进行序列化时会丢失;
- 不支持循环引用对象的拷贝
二、Object.assign(target, source)
默认是对对象进行深拷贝的,但是我们需要注意的是,它只对最外层的进行深拷贝,也就是当对象内嵌套有对象的时候,被嵌套的对象进行的还是浅拷贝
var obj1 = {
x: 1,
y: 2,
z: 3
}
var obj2 = Object.assign({}, obj1);
缺点:
- 针对的是对象自身可枚举的属性,对于不可枚举的没有效果;
- 只对最外层的进行深拷贝,也就是当对象内嵌套有对象的时候,被嵌套的对象进行的还是浅拷贝
提示:数组拷贝方法当中,使用...、slice、concat等进行拷贝也是一样的效果,只深拷贝最外层
三、自定义递归克隆函数
function deepClone(target) {
let newObj; // 定义一个变量,准备接新副本对象
// 如果当前需要深拷贝的是一个引用类型对象
if (typeof target === 'object') {
if (Array.isArray(target)) {// 如果是一个数组
newObj = []; // 将newObj赋值为一个数组,并遍历
for (let i in target) { // 递归克隆数组中的每一项
newObj.push(deepClone(target[i]))
}
// 判断如果当前的值是null;直接赋值为null
} else if(target===null) {
newObj = null;
// 判断如果当前的值是一个正则表达式对象,直接赋值
} else if(target.constructor===RegExp){
newObj = target;
}else {
// 否则是普通对象,直接for in循环递归遍历复制对象中每个属性值
newObj = {};
for (let i in target) {
newObj[i] = deepClone(target[i]);
}
}
// 如果不是对象而是原始数据类型,那么直接赋值
} else { newObj = target; }
// 返回最终结果
return newObj;
}
缺点:不能解决循环引用的问题和对象间互相引用的问题
四、使用lodash的_.cloneDeep()
解决了循环引用的问题和对象间互相引用的问题
var _ = require('lodash');
var obj1 = {
a: 1,
b: { c: { d: 1 } },
e: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);