Javascript手写深拷贝

77 阅读1分钟

区别引用赋值、浅拷贝和深拷贝 给出一个举例对象:

const info = {
    name:'jackson',
    friend:{
        name:'james'
    }
}

引用赋值:

在内存中的引用相同

const obj1 = info

obj1.name = 'alvin'
console.log(info.name) //'alvin'

浅拷贝

用解构操作符:
const obj2 = {...info}
obj2.name = 'kobe'
console.log(info.name) // jackson //没有被改变
obj2.friend.name = 'kobe'
cosole.log(info.friend.name) // kobe //仍然被改变

用Object.assign:
const obj3 = Object.assign({},info)
obj3.name = 'kobe'
console.log(info.name) // jackson //没有被改变
obj3.friend.name = 'kobe' 
console.log(info.friend.name) // kobe //仍然被改变

深拷贝 (JSON方法举例)

const obj4 = JSON.parse(JSON.stringify(info))
obj4.name = 'kobe' 
console.log(info.name) // jackson //没有被改变
obj4.friend.name = 'kobe'
console.log(info.friend.name) // james //没有被改变

方法一:用JSON

const b = JSON.parse(JSON.stringify(a))

缺点:

  1. 不支持Date 正则 undefined 函数等数据
  2. 不支持引用(即环状结构)
  3. 然后引出方法二

方法二:递归

要点:

  1. 递归
  2. 判断类型
  3. 检查环

const deepClone = (a,cache) => {
    if(!cache){
        cache = new Map()
    }
  //不考虑 iframe

  if (a instanceof Object) {
    if (cache.get(a)) {
    // 检查环
    return cache.get(a)
  }
    let result = undefined
    //Object
    if (a instanceof Function) {
      // 不能百分之百拷贝
      if (a.prototype) {
        //如果有prototype就是普通函数
        result = function () {
          return a.apply(this, arguments)
        }
      } else {
        //箭头函数
        result = (...args) => {
          a.call(undefined, ...args)
        }
      }
    } else if (a instanceof Array) {
      // 数组
      result = []
    } else if (a instanceof Date) {
      // 日期
      result = new Date(a - 0)
    } else if (a instanceof RegExp) {
      // 正则
      result = new RegExp(a.source, a.flags)
    } else {
      result = {}
    }
    cache.set(a, result)
    for (let key in a) {
      if (a.hasOwnProperty(key)) {
        //如果属性是继承得到的,不应该拷贝,在该对象上,再拷贝
        result[key] = deepClone(a[key],cache)
      }
    }
    return result
  } else {
    //string number boolean null undefined symbol bigint
    return a
  }
}
//测试代码
const a = {
  number: 1,
  bool: false,
  str: 'hi',
  empty1: undefined,
  empty2: null,
  array: [
    { name: 'frank', age: 18 },
    { name: 'jacky', age: 19 },
  ],
  date: new Date(2000, 0, 1, 20, 30, 0),
  regex: /\.(j|t)sx/i,
  obj: { name: 'frank', age: 18 },
  f1: (a, b) => a + b,
  f2: function (a, b) {
    return a + b
  },
}
a.self = a // 循环引用 没有出口
const b = deepClone(a)
b.self === b // true
b.self = 'hi'
a.self !== 'hi' //true

面试问到是什么深拷贝: 画图,表示两个对象直接没有交集,则是深拷贝。