当前位置: 首页>编程日记>正文

实现深拷贝和浅拷贝的方法

赋值

let obj1={a:1,b:2};
console.log(obj1);//输出{a:1,b:2}
let obj2=obj1;//浅拷贝
console.log(obj2);//输出{a:1,b:2}
obj1.a=5;
console.log(obj1);//输出{a:5,b:2}
console.log(obj2);//输出{a:5,b:2}

浅拷贝

展开语法、Array.prototype.concat()Array.prototype.slice()Array.from()Object.assign()Object.create()

扩展运算符(...)

let obj = {
    name: '张三',
    age: 23,
    address: undefined,
    sayHello: function () {
        console.log('Hello');
    },
    isStudent: false,
    job: {
        name: 'FE',
        money: 12
    },
    [Symbol('sy')]: 13

}
let newObj = { ...obj };
newObj.age = 16;
newObj.job.money = 22;
console.log(obj);//{name: '张三',age: 23, isStudent: false, job: {name: 'FE',money: 22},sayHello:ƒ(),Symbol(sy):13, address: undefined}
console.log(newObj);//{name: '张三',age: 16, isStudent: false, job: {name: 'FE',money: 22},sayHello:ƒ(),Symbol(sy):13, address: undefined}
newObj.sayHello() //Hello

arr.slice(begin, end);

var arr = [2, 4, 6, { y: 10 }]
var newArr = arr.slice()
newArr[0] = 10
newArr[3].x = 20
newArr[3].y = 30
console.log(JSON.stringify(arr)) //[2,4,6,{"y":30,"x":20}]
console.log(JSON.stringify(newArr)) //[10,4,6,{"y":30,"x":20}]

arr.concat()

var arr = ["Chinese", { "name": "zs" }, "French"]
var arr1 = arr.concat()
arr1[1].name = "ls"
arr1[2] = "China"
console.log(JSON.stringify(arr)); //["Chinese",{"name":"ls"},"French"]
console.log(JSON.stringify(arr1)); //["Chinese",{"name":"ls"},"China"]

Object.assign(target, …sources)

let obj = {
    name: '张三',
    age: 23,
    address: undefined,
    sayHello: function () {
        console.log('Hello');
    },
    isStudent: false,
    job: {
        name: 'FE',
        money: 12
    },
    [Symbol('sy')]: 13
}
var newObj = {}
Object.assign(newObj, obj)
newObj.age = 16;
newObj.job.money = 22;
console.log(obj);//{name: '张三',age: 23, isStudent: false ,job: {name: 'FE',money: 22},sayHello:ƒ(),Symbol(sy):13, address: undefined}
console.log(newObj);//{name: '张三',age: 16, isStudent: false, job: {name: 'FE',money: 22,,sayHello:ƒ(),Symbol(sy):13, address: undefined}}
newObj.sayHello() //Hello

由上案例可以看出,扩展运算符(...)、concat、slice、assign只对obj对象中属性为基本数据类型的值进行了深拷贝,引用类型的值为浅拷贝。

深拷贝

第一种:配合使用JSON.parse()和JSON.stringify()两个函数(局限性比较大)
  • 会忽略属性值为undefined的属性
  • 会忽略属性为Symbol的属性
  • 不会序列化函数和正则表达式类型
  • 会抛弃对象的constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object
  • 不能解决循环引用的问题,直接报错
    let obj = {
        name: '张三',
        age: 23,
        address: undefined,
        sayHello: function () {
            console.log('Hello');
        },
        isStudent: false,
        job: {
            name: 'FE',
            money: 12
        },
        [Symbol('sy')]:13

    }
    let newObj = JSON.parse(JSON.stringify(obj)); 
    obj.job.money = 21;

    console.log(JSON.stringify(obj)); //{"name":"张三","age":23,"isStudent":false,"job":{"name":"FE","money":21}}
    console.log(newObj.name);      // 输出张三
    console.log(newObj.age);       // 输出23
    console.log(newObj.job.money); // 输出12
    console.log(newObj.address);   // 报错
    console.log(newObj.sayHello());// 报错 Uncaught TypeError: newObj.sayHello is not a function
第二种: 实现自己简易的深拷贝函数
//此写法会忽略属性为Symbol的属性
function deepClone(obj) {
    if (typeof obj !== "object") return;
    let newObj = obj instanceof Array ? [] : {};
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            newObj[key] = typeof obj[key] === "object" ? deepClone(obj[key]) : obj[key];
        }
    }
    return newObj;
}

// 不忽略Symbol
function deepClone(obj){
    if (typeof obj !== "object") return;
    let newObj = obj instanceof Array ? [] : {};
    for (var i = 0; i < Reflect.ownKeys(obj).length; i++) {
        let key = Reflect.ownKeys(obj)[i]
        if(obj.propertyIsEnumerable(key)){
            newObj[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) : obj[key];
        }
    }
    return newObj;
}

let obj = {
    name: '张三',
    age: 23,
    address: undefined,
    sayHello: function () {
        console.log('Hello');
    },
    isStudent: false,
    job: {
        name: 'FE',
        money: 12
    },
    [Symbol('sy')]: 13

}
let newObj = deepClone(obj);
console.log(newObj);   
console.log(newObj.name);      // 输出张三
console.log(newObj.age);       // 输出23
console.log(newObj.job.money); // 输出12
console.log(newObj.address);   // undefined
console.log(newObj.sayHello());// 报错 Uncaught TypeError: newObj.sayHello is not a function
第三种方法:函数库lodash的 _.cloneDeep 方法
let obj = {
  name: '张三',
  age: 23,
  isStudent: false,
  job: {
    name: 'FE',
    money: 12
  }
}
let newObj = _.cloneDeep(obj);
obj.job.money = 21;
console.log(newObj.name);     // 输出张三
console.log(newObj.age);      // 输出23
console.log(newObj.job.money);// 输出12
第四种:jQuery.extend()方法

jQuery有提供一个 实现深拷贝和浅拷贝的方法,.extend 可以用来做深拷贝。,第1张.extend(deepCopy, target, object1, [objectN]) //第一个参数为true,就是深拷贝

let obj = {
    a: {
        c: 1,
        d: [1, 3, 5],
    },
    b: 2
}
let newObj = $.extend(true, {}, obj);
obj.b = 20; 
console.log(newObj.b); //输出2
第五种 JS原生的深拷贝:structuredClone()
  • Function 类型会报错
let obj = {
    name: '张三',
    age: 23,
    address: undefined,
    a:null,
    b:new Date(),
    c:new RegExp(/\d/),
    d:new Error('dd'),
    isStudent: false,
    job: {
        name: 'FE',
        money: 12
    },
    [Symbol('sy')]: 13

}
let newObj = structuredClone(obj);

相关文章: