手写系列——JS深拷贝和浅拷贝

不要问我心里有没有你,我余光中都是你。——余光中

image.png

一直想做个手写的专题,之前也写了一部分,后面会陆陆续续的挪到这里,今天只是写一些相对简单的手写系列,之后会有更加深入的研讨。

概念补漏

1. 堆栈的概念

在计算机中,堆栈是两种数据结构。

  • 栈(stack):先进后出;动态分配的空间 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。
  • 堆(heap):队列优先,先进先出;由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。

2.基本,引用数据类型

  • 7种基本数据类型: Undefined、Null、Boolean、Number、String、Symbol(es6新增)、BigInt(es10新增), 基本数据类型都存储在栈中,每种数据类型的内存空间大小是确定的,所以便于及时回收,更加容易管理内存空间。
  • 1种引用数据类型: Object 。这其中包含了 object、array、function、date等等,这样的数据存储于堆中。 但是其引用类型的数据存储在栈内存中,如果需要访问可以通过先获取到对象的指针地址,然后通过指针地址访问堆中的对应数据。

JavaScript不支持任何创建自定义类型的机制,而所有值最终都将是以上 8 种数据类型之一(排除之后新增)。

  • 为了便于理解我做了一个示范。


    image.png
  • 堆栈图


    image.png

3.浅拷贝和深拷贝
浅拷贝:简单的说浅拷贝就是只进行一层的拷贝,对对象的属性第一层进行拷贝,不管之后的层级。
深拷贝:对对象的属性无限层级的拷贝。

代码示范

这是我觉得现在比较好的深浅拷贝方式,随着语言的发展,之后类型的增多,会有一定的增删。

  • 浅拷贝
// shallowCopy

const isObject = (o) => typeof o === 'object' && o !== null;

const shallowCopy = (obj) => {
  if (!isObject(obj)) return obj;

  const res = Array.isArray(obj) ? [] : {};

  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      const element = obj[key];
      res[key] = element;
    }
  }
  return res;
};
  • 深拷贝
// deepCopy

const isObject = (o) => typeof o === 'object' && o !== null;

const deepCopy = (obj, weakmap = new WeakMap()) => {
  if (!isObject(obj)) return obj;
  // 解决循环引用, 防止无限遍历
  if (weakmap.get(obj)) return weakmap.get(obj);

  // 创建新对象存入weakmap
  const target = Array.isArray(obj) ? [] : {};
  weakmap.set(obj, target);

  // symbol拷贝
  const symArr = Object.getOwnPropertySymbols(obj);
  symArr.forEach((key) => {
    if (isObject(obj[key])) {
      target[key] = deepCopy(obj[key], weakmap);
    } else target[key] = obj[key];
  });

  // 对象的key
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      if (isObject(obj[key])) {
        target[key] = deepCopy(obj[key], weakmap);
      } else target[key] = obj[key];
    }
  }
  return target;
};

参考文档

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。