前端工具包之深浅拷贝

1,938 阅读2分钟

前言

我们在开发过程中,总会封装一些公共函数来作为我们的工具来简化代码或者复用代码,为此,我打算整理一下我日常工作中常用的一些封装的工具函数,本篇文章为对象、数组的deepClone函数封装。

系列文章

1.前端工具包之深浅拷贝

2.前端工具包之日期格式化

3.前端工具包之防抖函数

4.前端工具包之小工具

5.前端工具包之log美化

背景

let a = {
    age: 1
}
let b = a
a.age = 2
console.log(b.age) // 2

从上述例子中我们可以发现,如果给一个变量赋值一个对象,那么两者的值会是同一个引用,其中一方改变,另一方也会相应改变。

但是通常在开发中我们不希望出现这样的问题,我们可以使用浅拷贝来解决这个问题。

解析

浅拷贝

首先可以通过 Object.assign 或 展开运算符 ... 来解决这个问题。

let a = {
    age: 1
}
let b = Object.assign({}, a) // or {...a}
a.age = 2
console.log(b.age) // 1

通常浅拷贝就能解决大部分问题了,但是当我们遇到如下情况就需要使用到深拷贝了

let a = {
    age: 1,
    jobs: {
        first: 'FE'
    }
}
let b = {...a}
a.jobs.first = 'native'
console.log(b.jobs.first) // native

浅拷贝只解决了第一层的问题,如果接下去的值中还有对象的话,那么就又回到刚开始

深拷贝

let a = {
    age: 1,
    jobs: {
        first: 'FE'
    }
}
let b = JSON.parse(JSON.stringify(a))
a.jobs.first = 'native'
console.log(b.jobs.first) // FE

但是该方法也是有局限性的:

  • 会忽略 undefined
  • 会忽略 symbol
  • 不能序列化函数
  • 不能解决循环引用的对象

在遇到functionundefined 或者 symbol 的时候,该对象也不能正常的序列化

let a = {
    age: undefined,
    sex: Symbol('male'),
    jobs: function() {},
    name: 'wb'
}
let b = JSON.parse(JSON.stringify(a))
console.log(b) // {name: "wb"}

你会发现在上述情况中,该方法会忽略掉函数和 undefined 。

但是在通常情况下,复杂数据都是可以序列化的,所以这个函数可以解决大部分问题,并且该函数是内置函数中处理深拷贝性能最快的。当然如果你的数据中含有以上三种情况下,可以使用递归来实现一个深拷贝方法,因此,这里就封装一个工具函数来供实现深拷贝。

工具封装

首先使用 Object.prototype.toString.call 实现一个精准判断类型的辅助函数,再借助递归实现深拷贝

// 精准判断类型函数
function  typeOf (obj) {
  const  toString = Object.prototype.toString
  const  map = {
    '[object Boolean]': 'boolean',
    '[object Number]': 'number',
    '[object String]': 'string',
    '[object Function]': 'function',
    '[object Array]': 'array',
    '[object Date]': 'date',
    '[object RegExp]': 'regExp',
    '[object Undefined]': 'undefined',
    '[object Null]': 'null',
    '[object Object]': 'object'
  }
  return map[toString.call(obj)]
}
// util 深拷贝函数
export function deepCopy (data) {
  const t = typeOf(data)
  let o
  if (t === 'array') {
    o = []
  } else if (t === 'object') {
    o = {}
  } else {
    return data
  }
  if (t === 'array') {
    for (let i = 0; i < data.length; i++) {
      o.push(deepCopy(data[i]))
    }
  } else if (t === 'object') {
    for (let i in data) {
      o[i] = deepCopy(data[i])
    }
  }
  return o
}

开源库

个人主页 | bin-ui | bin-admin