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

179 阅读2分钟

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

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;
};

参考文档

文章有帮助 请动动小手点个赞吧