深拷贝(递归实现deepClone)

3,621 阅读3分钟

第一次在掘金写笔记,若有错误,还请指出哈!写的不好的地方,还请多多包涵!

激动中瑟瑟发抖

js分基本数据类型和引用数据类型。

基本数据类型:Number String Boolean Symbol undefined null,存储在当中,动态分配的内存,大小不定也不会自动释放。

引用数据类型:object中存储地址,自动分配内存空间。地址(0xffff) -> 堆中的内容

浅拷贝:对于 基本数据类型 来说,修改拷贝前后互不影响;对于 引用数据类型来说,修改拷贝前后第一层互不影响,但是 修改深层次内容会有影响,因为拷贝前后的变量指向的是同一块内存空间

深拷贝:针对引用数据类型多层而言,深拷贝相当于在内存空间内重新开辟了新的空间存储值,所以修改拷贝前后的变量不会互相影响。

常见的浅拷贝方法:

  • Object.assign()
  • 展开运算符(...)
  • 自己通过js实现

常见的深拷贝方法:

  • 递归 遍历,一个值一个值的拷贝(本文主要介绍递归方式的实现
  • JSON.stringfy() & JSON.parse(),function 和 undefined 不可用
  • lodash
  • JQuery的 $.extend([deep], target, object1 [, objectN ]) 方法,通过第一个参数为true 或者 false 来指定深浅拷贝

好了,下面咱们进入正题:

/**
 * 判断变量的类型
 * @param {object} value 变量值
 */
function checkType(value) {
  return Object.prototype.toString.call(value).slice(8, -1);
}

/**
 * 深拷贝(递归)
 * @param {*} sourceValue 需要拷贝的值
 */
function deepClone(sourceValue) {
  // 如果传入的数据是简单类型(不是 {} & []),直接返回即可
  if (typeof sourceValue !== "object") {
    return sourceValue;
  }
  // 判断 传入参数的数据类型(object or array)
  let targetType = checkType(sourceValue);
  // 根据传入参数的数据类型,创建 初始存储结果的变量类型 {} or []
  let result = targetType === "Object" ? {} : [];
  // 遍历 sourceValue (for...in可以遍历数据和对象)
  // 避免数组内有自定义属性,遍历数组使用 for...of,遍历对象 for...in
  if (targetType === "Array") {
    // 传入参数是数组时,次数使用的是 for...of 遍历,当然,也可以使用 数组的其他遍历方法
    for (const [key, value] of sourceValue.entries()) {
      let itemType = checkType(item);
      // 如果 value 是 数组 或 对象,则继续遍历
      if (itemType === "Object" || itemType === "Array") {
        result[key] = deepClone(value);
      } else {
        // 如果 value 是 基本数据类型 或者 函数,直接赋值即可
        result[key] = value;
      }
    }
  } else {
    // 传入参数是对象时
    for (const key in sourceValue) {
      // 遍历数组时,key 为数组的 下标
      // 遍历对象时,key 为对象的 key
      // hasOwnProperty 只能检验对象自身的属性,不能检验继承属性,也不能检验原型链上的属性
      if (sourceValue.hasOwnProperty(key)) {
        const item = sourceValue[key];
        let itemType = checkType(item);
        // 如果 value 是 数组 或 对象,则继续遍历
        if (itemType === "Object" || itemType === "Array") {
          result[key] = deepClone(item);
        } else {
          // 如果 value 是 基本数据类型 或者 函数,直接赋值即可
          result[key] = item;
        }
      }
    }
  }
  // 返回 result 即可
  return result;
}

嗯嗯,第一次分享就到这儿啦!!!
虽然知识简单而且少的可怜!!!