深克隆方法总结

260 阅读2分钟

深克隆与浅克隆

  • 基本类型数据没有深浅克隆现象,所有复制的数据都互不影响
  • 引用类型数据存在深浅克隆现象,浅克隆只拷贝了地址,两者的操作互相影响,深克隆 完全 拷贝了堆区的数据,两者的操作互不影响

克隆数据的方法

= 相对以下方法,=谈不上是一个克隆方法,只算是一个引用
Object.assign 浅克隆,用于对象,返回的也是一个新的对象,但操作属性中出现的引用类型仍会造成干扰
concat 浅克隆,用于数组,返回的也是一个新的数组,但操作元素中出现的引用类型仍会造成干扰
slice 浅克隆,用于数组,返回的也是一个新的数组,但操作元素中出现的引用类型仍会造成干扰
JSON.parse(JSON.stringfy()) 深克隆,但数据中的函数拷贝不了也无法执行

选择用什么方式进行数据复制要看数据里的内容来选择,里面都是基本类型的数据那深浅拷贝也无所谓。


利用数据类型判断、for in遍历数组或对象、递归

实现一个深度克隆方法

思路:

  • 要克隆数据,那首先得知道目标数据的类型
  • 需要深克隆的数据一般为数组和对象
  • 不需要深克隆的数据为基本数据类型(这里可以判断为非Array非Object)
  • 遍历需要克隆的 数组/对象 的 元素/键=值,扔进新建的空数组/空对象中完成组装
  • 考虑到 数组/对象 中的 元素/属性 仍可能为数组或对象,那么这需要判断元素/值的类型 递归组装操作

使用到的方法:判断类型,组装数组/对象(for in遍历)

const obj = {
    a: 'alan',
    fun() {
        console.log('fun !!');
    },
    obj: {
        hello: 'hello'
    },
    arr: [1, 2, 3, 4, { world: 'world' }, [4, 3, 2, 1]]
};
const arr = [1, 2, 3, 4, { world: 'world' }, [4, 3, 2, 1]];


/* 
    深度克隆
*/
function deepClone(data) {
    // 判断类型
    function checkDataType(data) {
        return Object.prototype.toString.call(data).slice(8, -1);
    }
    const dataType = checkDataType(data);

    // init newData
    let newData;
    if (dataType === 'Array') newData = [];
    else if (dataType === 'Object') newData = {};
    else return newData = data;

    // compound newData
    for (let key in data) {
        // if:剔除遍历原型上的属性
        if (data.hasOwnProperty(key)) {
            const subDataType = checkDataType(data[key]);            
            if (subDataType !== 'Array' && subDataType !== 'Object') {
                newData[key] = data[key];
            }else{                
                newData[key] = deepClone(data[key]);
            }
        }
    }
    return newData;
}
// testOne
Array.prototype.protoPPPP = '你知道我是谁吗!!!';
const newArr = deepClone(arr);
arr[4].world = 'i change';
console.log(arr);
console.log(newArr);

// testTwo
const newObj = deepClone(obj);
obj.arr[4].world = 'i change';
console.log(obj);
console.log(newObj);
newObj.fun();