深拷贝与浅拷贝

108 阅读1分钟

深浅拷贝

深拷贝与浅拷贝

  • 从堆内存中开辟新的区域存放新对象
  1. 浅拷贝
  • 创建一个新对象,这个对象是原始对象属性的精确拷贝
    • 基本类型:拷贝值
    • 引用类型:拷贝内存地址
  • 对象的引用类型修改会相互影响
  1. 深拷贝
  • 修改新对象不会相互影响

拷贝与赋值的区别

  • 赋值赋的是对象在栈中的地址,而不是堆中的数据,对象间会相互影响
  • 浅拷贝:重新在堆中创建内存,基本数据类型不会相互影响,但引用类型会相互影响
  • 深拷贝:对对象中的子对象进行递归拷贝,拷贝的两个对象互不影响

实现方式

  1. 浅拷贝的实现方式
  • Object.assign()
    • let obj2 = Object.assign({}, obj1)
  • ...
    • let obj2 = {...obj1}
  • concat
  • lodash clone
  • var newObject = $.extend({}, oldObject);
  1. 深拷贝的实现方式
  • let obj2 = JSON.parse(JSON.stringify(obj1))
    • 会忽略 undefined
    • 无法拷贝一些特殊的对象,诸如 RegExp, Date, Set, Map等
    • 无法拷贝函数(划重点)。
    • 会抛弃对象的constructor,所有的构造函数会指向Object
    • 不能解决循环引用的对象
  • var newObject = $.extend(true, {}, oldObject);
  • lodash deepClone

手写深拷贝

  • 若属性为值类型,则直接返回;若属性为引用类型,则递归遍历。
function deepClone(obj) {
    // 如果是 值类型 或 null,则直接return
    if(typeof obj !== 'object' || obj === null) {
        return obj
    }
       // 定义结果对象
    let copy = {}
    // 如果对象是数组,则定义结果数组
    if(obj.constructor === Array) {
        copy = []
    }
    // 遍历对象的key
    for(let key in obj) {
        // 如果key是对象的自有属性
        if(obj.hasOwnProperty(key)) {
            // 递归调用深拷贝方法
            copy[key] = deepClone(obj[key])
        }
    }
    return copy
} 

  • 解决循环引用:创建一个WeakMap。记录下已经拷贝过的对象,如果说已经拷贝过,那直接返回它行了。