2020前端面试复习-js部分-数组和对象的深拷贝

114 阅读3分钟

数组和对象的深拷贝

浅克隆:只克隆第一级,对于后代级别还是公用之前的

1.新客隆的obj2的某些操作还是可以改变obj1中的内容的

对象的克隆

let obj1={
    name:'xxx',
    course:{
        c1:'语文'c2:'数学'
    }
};
console.log(obj1)
let obj2 = obj1
//不是克隆,只是在那个obj1和obj2公用同一个对内训,所谓克隆最起码是赋值一份一摸一样的,用全新的地址
  1. 克隆1:循环遍历(浅克隆)
let obj2={};
keys = [...Object.keys(obj1),
        ...Object.getOwnPropertySymbols(obj1);
        ];
keys.forEach(key=>{
    obj2[keys]=obj1[keys]
})
console.log(obj2);
  1. 克隆2:基于展开运算符(浅克隆)
let obj2 = {...obj1}
console.log(obj2===obj1);//false
console.log(obj2.course===obj1.cours);//true
  1. 克隆3:基于Object.assign([obj1],[obj2])(浅克隆);返回的结果依然是obj1堆内存,只不过是把obj2中的键值对和原始obj1的键值对合并在一起
let obj2 = Object.assign(obj1,{})//obj2===obj1->true
let obj2 = Object.assign({},obj1)//obj2===obj1->false
cons ole.log(obj2.course===obj1.cours);//true

数组的克隆

let arr1 = [10,20,[30,40]]
  1. 克隆1:循环foreach/map(浅克隆)
let arr2 = [];
arr1.forEach((item,index)=>{
    arr2[index] = item;
})
arr2=arr1.map(item=>item)
console.log(arr2 === arr1)
consoel.log(arr2[2] === arr1[2])
  1. 克隆2:基于展开运算符或者Object.assign(浅克隆)
  2. 克隆3:基于slice、concat...这些可以实现
let arr2 = arr1.slice()

深克隆:当前级及其所有的后代级别,最后都会克隆一份一摸一样的,和原始数据结构不存在任何关联

  • 消耗内存空间
let obj1={
    name:'xxx',
    course:{
        c1:'语文',
        c2:'数学'
    }
};
let arr1 = [10,20,[30,40]]
  1. 深克隆1:JSON.stringify/JSON.parse
    1. 基于stringify,把原始的对象(或者数组)变成一个字符串
    2. 再基于parse,把字符串转换为对象,此时对象对应的每个级的堆内存,都是全新开辟的
    3. 存在的问题:JSON.stringify变为字符串,很多类型不支持
      1. 正则、Math对象会被处理为空对象
      2. 具备函数、symbol属性值的属性直接被干掉了
      3. bigint处理不了,会报错
      4. 日期对象最后还是字符串
      5. ...
let obj2 = JSON.parse(JSON.stringify(obj1))
let arr2 = JSON.parse(JSON.stringify(arr1))
console.log(obj2===obj1);//false
console.log(obj2.course===obj1.cours);//false
console.log(arr2 === arr1)//false
consoel.log(arr2[2] === arr1[2])//false

浅克隆

//检测数据类型的方法封装
(function () {
    var getProto = Object.getPrototypeOf;
    var class2type = {};
    var toString = class2type.toString;
    var hasOwn = class2type.hasOwnProperty;
    var fnToString = hasOwn.toString;
    var ObjectFunctionString = fnToString.call(Object);

    [
        "Boolean",
        "Number",
        "String",
        "Symbol",
        "Function",
        "Array",
        "Date",
        "RegExp",
        "Object",
        "Error"
    ].forEach(function (name) {
        class2type["[object " + name + "]"] = name.toLowerCase();
    });

    function toType(obj) {
        if (obj == null) {
            return obj + "";
        }
        return typeof obj === "object" || typeof obj === "function" ?
            class2type[toString.call(obj)] || "object" :
            typeof obj;
    }
    window.toType = toType;
})();
//获取所有的私有属性,包含symbol私有属性(数组不获取其symbol )
function getOwnPropertys(obj){
    if(obj == null) return[];
    return [
        ...Object.keys(obj),
        ...Object.getOwnPropertySymbol(obj)
    ]
}
function shallowClone(obj){
    //处理其他类型值的克隆 
    let type = toType(obj);
    if(/^(number|string|boolean|null|undefined/symbol|bigint)$/.test(type)) return obj;
    if(/^(function)$/.test(type)) {
        //返回一个不同的函数,但是最后执行的效果和原始函数一致
        return function proxy(){
            return obj();
        };
    }
    if(/^(object|date)$/.test(type)) {
    //返回一个不同的函数,但是最后执行的效果和原始函数一致
    return new obj.constructor(obj);
    if(/^error$/.test(type)) {
    return new Error(obj.message);
}
    //只处理数组(最后返回的是数组)和对象(普通对象和类数组对象最后返回的都是普通对象)
    let keys = getOwnPropertys(obj),
        clone = {};
    Array.isArray(obj)?clone=[]:null;
    keys.forEach(key=>{
        clone[key]=obj[key]
    })
    <!-- for(let i =0;j<keys.length;i++){
        let key = keys[i];
        clone[key]=obj[key];
    } -->
    return clone
}

深克隆

function deepclone(obj,cache=new Set()){
    //只有数组和对象我们再处理深克隆,其余情况 直接按照浅克隆处理
    let type = toType(obj);
    if(!/^(object|array)$/.test(type)) return shallowClone(obj);
    //避免自己嵌套自己
    if(cache.has(obj)) return shallowclone(obj);
    cache.add(obj);
    let keys = getOwnPropertys(obj),
        clone = {};
    type === "array"?clone =[]:null;
    keys.forEach(key=>{
        clone[key]=deepclone(obj[key],cache);
    });
    return clone
}