JavaScript之深拷贝与浅拷贝

深拷贝和浅拷贝

  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技术分享原创和收集

发表评论 (审核通过后显示评论):