JavaScript之深拷贝与浅拷贝

作者: 慕时_木雨凡 | 来源:发表于2019-10-30 11:47 被阅读0次

    深拷贝和浅拷贝

    1. 深拷贝:改变拷贝后的结果,不会影响拷贝之前的内容
    2. 浅拷贝:改变拷贝后的结果,会影响拷贝之前的内容

    最常用的 es6 ...扩展运算符 实现拷贝

    // 单层对象 -- 深拷贝
    let obj = {name: 'mushi', age: 28}
    let copy = {...obj}
    obj.age = 29
    console.log(obj, copy) // { name: 'mushi', age: 29 } { name: 'mushi', age: '28' }
    
    // 对象嵌套 -- 浅拷贝
    let obj1 = {name: 'mushi', age: 28, job: [1,2]}
    let copy1 = {...obj1}
    obj1.job.push(3)
    console.log(obj1, copy1) // { name: 'mushi', age: 28, job: [ 1, 2, 3 ] } { name: 'mushi', age: 28, job: [ 1, 2, 3 ] }
    
    

    Object.assign() 实现拷贝

    // 单层对象 -- 深拷贝
    let obj = {name: 'mushi', age: 28}
    let copy = Object.assign({}, obj)
    obj.age = 29
    console.log(obj, copy) // { name: 'mushi', age: 29 } { name: 'mushi', age: '28' }
    
    // 对象嵌套 -- 浅拷贝
    let obj1 = {name: 'mushi', age: 28, job: [1, 2]}
    let copy1 = Object.assign({}, obj1)
    obj1.job.push(3)
    console.log(obj1, copy1) // { name: 'mushi', age: 28, job: [ 1, 2, 3 ] } { name: 'mushi', age: 28, job: [ 1, 2, 3 ] }
    
    

    Array.slice() 和 Array.concat()

    // 单层数组 -- 深拷贝
    let a = [1,2,3]
    let b = a.slice(); // let b = a.concat([])
    a.push(4)
    console.log(a, b) // [ 1, 2, 3, 4 ] [ 1, 2, 3 ]
    
    
    // 嵌套数组 -- 浅拷贝
    let c = [1,2,3, ['a', 'b']]
    let d = c.slice(); // let d = c.concat([])
    c[3].push('c')
    console.log(c, d) // [ 1, 2, 3, [ 'a', 'b', 'c' ] ] [ 1, 2, 3, [ 'a', 'b', 'c' ] ]
    

    JSON.parse 和 JSON.stringify实现深拷贝

    1. 效率比较低
    2. 不能实现复杂的深拷贝Map, Set, RegExp, Date, ArrayBuffer 和其他内置类型在进行序列化时会丢失
    let obj = {a: 1, b: 2, c: {d: 3}}
    let copy = JSON.parse(JSON.stringify(obj))
    obj.c.d = 300
    console.log(obj, copy) // { a: 1, b: 2, c: { d: 300 } } { a: 1, b: 2, c: { d: 3 } }
    

    对象中包含一些内置对象或者函数对象

    // 拷贝函数对象会丢失
    let obj = {a: 1, b: () => {}}
    let copy = JSON.parse(JSON.stringify(obj))
    obj.a = 2
    console.log(obj, copy) // { a: 2, b: [Function: b] } { a: 1 }
    
    // 拷贝内置对象会丢失
    let obj1 = {a: 1, b: new RegExp()}
    let copy1 = JSON.parse(JSON.stringify(obj1))
    obj1.a = 2
    console.log(obj1, copy1) // { a: 2, b: /(?:)/ } { a: 1, b: {}}
    

    自己封装deepCopy函数进行深拷贝

    1. 利用for in 循环进行拷贝
    2. 排除一些其他异常数据
    3. 使用new WeakMap()对拷贝过的数据进行存储防止重复循环引用
    4. 递归循环
    function deepCopy (obj, hash = new WeakMap()) {
        if (obj === null || obj === undefined) return obj;
        if (obj instanceof Date) return new Date(obj);
        if (obj instanceof RegExp) return new RegExp(obj);
        if (typeof obj !== 'object') return obj; // 函数是不需要深拷贝的
        if (hash.get(obj)) return hash.get(obj); // 如果obj被拷贝过就直接返回
        let cloneObj = new obj.constructor; // 申明一个cloneObj类型obj保持一致
        hash.set(obj, cloneObj) // 将当前对象和拷贝对象存入hash中
        for (let key in obj) {
            if (obj.hasOwnProperty(key)) {
                cloneObj[key] = deepCopy(obj[key], hash)
            }
        }
        return cloneObj
    }
    let obj = {a: 1, b: {c: 2, d: 3}}
    let copy = deepCopy(obj);
    obj.a = 100
    console.log(obj, copy) // { a: 100, b: { c: 2, d: 3 } } { a: 1, b: { c: 2, d: 3 } }
    

    相关文章

      网友评论

        本文标题:JavaScript之深拷贝与浅拷贝

        本文链接:https://www.haomeiwen.com/subject/whdovctx.html