对象深度拷贝

4年以前  |  阅读数:388 次  |  编程语言:JavaScript 
//JSON.stringify深度克隆对象;
//1.无法对函数 、RegExp等特殊对象的克隆;
//2.会抛弃对象的constructor,所有的构造函数会指向Object;
//3.对象有循环引用,会报错
const objDeepClone = obj = > {
    return clone(obj)
}

const isType = (obj, type) = > {
    if (typeof obj !== 'object') return false;
    // 判断数据类型的经典方法:
    const typeString = Object.prototype.toString.call(obj);
    let flag;
    switch (type) {
    case 'Array':
        flag = typeString === '[object Array]';
        break;
    case 'Date':
        flag = typeString === '[object Date]';
        break;
    case 'RegExp':
        flag = typeString === '[object RegExp]';
        break;
    default:
        flag = false;
    }
    return flag;
};

/**
 * deep clone
 * @param  {[type]} parent object 需要进行克隆的对象
 * @return {[type]}        深克隆后的对象
 */
const clone = parent = > {
    // 维护两个储存循环引用的数组
    const parents = []
    const children = []

    const _clone = parent = > {
        if (parent === null) return null
        if (typeof parent !== 'object') return parent

        let child, proto

        if (isType(parent, 'Array')) {
            // 对数组做特殊处理
            child = []
        } else if (isType(parent, 'RegExp')) {
            // 对正则对象做特殊处理
            child = new RegExp(parent.source, getRegExp(parent))
            if (parent.lastIndex) child.lastIndex = parent.lastIndex
        } else if (isType(parent, 'Date')) {
            // 对Date对象做特殊处理
            child = new Date(parent.getTime())
        } else {
            // 处理对象原型
            proto = Object.getPrototypeOf(parent)
            // 利用Object.create切断原型链
            child = Object.create(proto)
        }

        // 处理循环引用
        const index = parents.indexOf(parent)

        if (index !== -1) {
            // 如果父数组存在本对象,说明之前已经被引用过,直接返回此对象
            return children[index]
        }
        parents.push(parent)
        children.push(child)

        for (const i in parent) {
            // 递归
            child[i] = _clone(parent[i])
        }

        return child
    }
    return _clone(parent)
}

console.log(objDeepClone({
    name: '张三',
    age: 23,
    obj: {
        name: '李四',
        age: 46
    },
    arr: [1, 2, 3]
})) // { name: '张三', age: 23, obj: { name: '李四', age: 46 }, arr:[ 1, 2, 3 ] }

Copyright© 2013-2020

All Rights Reserved 京ICP备2023019179号-8