深拷贝和浅拷贝

浅拷贝

代码示例-1 直接赋值

let obj = {
    name: 'mary',
    age: 12,
    parents: {
        father: 'a',
        mother: 'b',
    }
}
let obj2 = obj;
obj2.age = 13;
console.log(obj, obj2); 
// {name: 'mary', age: 13, parents: {father: 'a', mother: 'b'} {name: 'mary', age: 13, parents: {father: 'a', mother: 'b'}
obj2.parents.father = 'c';
console.log(obj, obj2); 
// {name: 'mary', age: 13, parents: {father: 'c', mother: 'b'} {name: 'mary', age: 13, parents: {father: 'c', mother: 'b'}

复制代码

如上代码所示 这是一种直接赋值的方式 两个指向的都是同一块地址 这样会导致 当 其中任意一个对象改变了其里面的属性的时候 则另外一个对象也会发生改变

代码示例-2 浅拷贝的API方式

  • Object.assign()

针对对象

  • 扩展运算符 concat() slice()

这三个都是针对数组类型的

let obj = {
    name: 'mary',
    age: 12,
    parents: {
        father: 'a',
        mother: 'b',
    }
}
let obj2 = Object.assign({}, obj);
obj2.age = 13;
console.log(obj, obj2); 
// {name: 'mary', age: 12, parents: {father: 'a', mother: 'b'} {name: 'mary', age: 13, parents: {father: 'a', mother: 'b'}
obj2.parents.father = 'c';
console.log(obj, obj2); 
// {name: 'mary', age: 12, parents: {father: 'c', mother: 'b'} {name: 'mary', age: 13, parents: {father: 'c', mother: 'b'}


let arr1 = [1, 2, 3, { name: 'jack' }];
let arr2 = arr1.concat();
let arr3 = [... arr1];
let arr4 = arr1.slice();
复制代码

可以看到 如果是浅拷贝的方式 那么obj obj2指向的就不是同一个引用的地址 但是限制在于只能拷贝第一层 也就是说当对象里面再去嵌套对象的时候 那么 里面的对象引用的还是同一个地址 如上面的parent 当obj2去改变里面的数据的时候 也会导致obj里面的parent的数据发生改变

代码示例-3 浅拷贝的手动实现

function shallowClone(target) {
    if(typeof target === "object" && target !== null){
        const cloneTarget = Array.isArray(target) ? [] : {};
        for(let prop in target){
            if(target.hasOwnProperty(prop)){
                cloneTarget[prop] = target[prop];
            }
        }
        return cloneTarget;
    }else{
        return target;
    }
}
复制代码

深拷贝

深拷贝的API方式

代码示例

let obj = {
    name: 'mary',
    age: 12,
    parents: {
        father: 'a',
        mother: 'b',
    }
}
let obj2 = JSON.parse(JSON.stringify(obj));
obj2.age = 13;
console.log(obj, obj2); 
// {name: 'mary', age: 12, parents: {father: 'a', mother: 'b'} 
// {name: 'mary', age: 13, parents: {father: 'a', mother: 'b'}
obj2.parents.father = 'c';
console.log(obj, obj2); 
// {name: 'mary', age: 12, parents: {father: 'a', mother: 'b'} 
// {name: 'mary', age: 13, parents: {father: 'c', mother: 'b'}
复制代码

可以看到深拷贝的方式解决了上面浅拷贝的的问题 可以进行深层次的拷贝

深拷贝的手写实现-1

function deepClone(target) {
    if(typeof target === "object" && target !== null){
        let cloneTarget = Array.isArray(target) ? [] : {};
        for(let prop in target){
            if(target.hasOwnProperty(prop)){
                cloneTarget[prop] = deepClone(target[prop]);
            }
        }
        return cloneTarget;
    }else{
        return target;
    }
}
复制代码

深拷贝手动实现-2 解决循环引用的问题

let obj = {
    name: 'mary',
    age: 12,
    parents: {
        father: 'a',
        mother: 'b',
    },
};
obj.same = obj;
复制代码

这样 就是一个循环引用的例子 会导致一直拷贝 最终爆内存
思路在于 可以创建一个 map 记录下已经拷贝的对象 如果这个对象已经被拷贝过 则直接返回就好了

function deepClone(target, map = new Map()) {
    if(map.get(target)){
        return target;
    }
    if(typeof target === "object" && target !== null){
        map.set(target, true);
        let cloneTarget = Array.isArray(target) ? [] : {};
        for(let prop in target){
            if(target.hasOwnProperty(prop)){
                cloneTarget[prop] = deepClone(target[prop], map);
            }
        }
        return cloneTarget;
    }else{
        return target;
    }
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享