javaScript深拷贝

82 阅读3分钟

javaScript深拷贝

首先要明白一个东西,javaScript没有完完全全的深拷贝,因为一个完美的深拷贝的话,你需要考虑到原生DOM/BOM对象、RegExp对象、函数、原型链处理的问题,浏览器兼容问题(不确定世上有没有这样一个完完全全的深拷贝方法),同时,深拷贝没有一个统一的定义,所以,不必追求一个通用完美的深拷贝,我们只需要根据我们的需求,选择最合适我们的一个深拷贝方法就可以了

Javascript中的数据分为原始值和引用值,对于原始值来说,它的值直接存储在栈内存中,而对于引用类型来说,它在栈内存中仅仅存储了一个引用,而真正的数据存储在堆内存中

浅拷贝

对于浅拷贝而言,就是只拷贝对象的引用,而不深层次的拷贝对象的值,多个对象指向堆内存中的同一对象,任何一个修改都会使得所有对象的值修改,因为它们公用一条数据

深拷贝

深拷贝不会拷贝引用类型的引用,而是将引用类型的值全部拷贝一份,形成一个新的引用类型,这样就不会发生引用错乱的问题,使得我们可以多次使用同样的数据,而不用担心数据之间会起冲突

JSON.parse(JSON.stringify())

const targetObj = JSON.parse(JSON.stringify(originObj));

利用JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反序列化(还原)js对象,但是只能处理合法的JSON对象

JSON对象对值得类型的规定

  • 复合类型的值只能是数组或对象,不能是函数、正则表达式对象、日期对象
  • 原始类型的值只有四种:字符串、数值(必须以十进制表示)、布尔值和null(不能使用NaN, Infinity, -Infinity和undefined)

由于JSON对象对值得类型的规定,所以用上述方法进行拷贝,会用一下问题

  • 不支持对时间对象、RegExp、Error对象、function,Symbol 类型,undefined、NaN、Infinity和-Infinity的拷贝
  • 会丢失构造函数

Object.assign(target, ...sources)

const targetObj = Object.assign({}, originObj1, originObj2, ...)

Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象分配到目标对象。它将返回目标对象。只对顶层属性做深拷贝,后面属性做的还是浅拷贝

lodash

const targetObj = _.cloneDeep(originObj)

这个暂时没发现什么问题

自己写一个

首先明确需求,支持的数据类型, 所有的原始类型,普通对象,数组,不支持原型链上属性的拷贝

deepClone(origin, target) {
  var target = target || {},
    toStr = Object.prototype.toString,
    arrStr = "[object Array]";
  for (var prop in origin) {
    if (origin.hasOwnProperty(prop)) {
      if (typeof (origin[prop] !== null && origin[prop]) === "object") { //判断是不是对象
        if (toStr.call(origin[prop]) === arrStr) { // 判断是不是数组
          target[prop] = [];
        } else {
          target[prop] = {};
        }
        deepClone(origin[prop], target[prop]); // 递归
      } else { // 原始值走这里
        target[prop] = origin[prop];
      }
    }
  }
  return target;
}