js实现克隆对象的方法

401 阅读2分钟

一、 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);