structuredClone 深拷贝小记

422 阅读3分钟

一、前言

  • 提到 JS 的深拷贝,你的脑海里可能会自动的浮现两个实现方式:
    • JSON.parse(JSON.stringify(obj))
    • lodash 的 cloneDeep
  • 上述两种深拷贝的方式都有一些缺点,因此在学习上述深拷贝方式的时候,你可能就想过,浏览器为啥不支持原生的深拷贝呢?这不 structuredClone 就来啦~浏览器运行时原生支持的深拷贝 API

二、JSON.parse(JSON.stringify(obj)) 的缺点

1、如果你的 obj 对象存在循环引用,那么该方法会报错

const obj = {a:1}; 
obj.b = obj;
const obj1 = JSON.parse(JSON.stringify(obj));

2、如果你的 obj 对象存在 Date 对象,该方法会将其转化成字符串

const obj = {date: new Date()}
const obj1 = JSON.parse(JSON.stringify(obj));
obj1.date;
typeof obj1.date;

3、如果你的 obj 对象中存在 Set、Map、正则、Error 对象,该方法会将其转成空对象字面量 { } ,如果存在 undefined,该方法会直接忽略

const obj = {
    set: new Set([1,2,3]),
    map: new Map([[2,2]]),
    reg: new RegExp(/123/),
    error: new Error('123'),
    none: undefined
}
JSON.parse(JSON.stringify(obj));

三、Lodash 可能存在的风险

1、Lodash 的 tree-shaking 可能和我们的使用心智有一些出入,如果你的项目脚手架没有处理该问题,你在引入方式也没有注意,那么会带来一些性能损耗。

四、structuredClone

1、MDN

  • 全局的 structuredClone() 方法使用结构化克隆算法将给定的值进行深拷贝。
  • 支持把原始值中的可转移对象转移到新对象,而不是把属性引用拷贝过去。 可转移对象与原始对象分离并附加到新对象;它们不可以在原始对象中访问被访问到。

2、 structuredClone 方法深拷贝的基础用法

// 普通深拷贝
const person = {
  name: "Timmy",
  gradutionDate: new Date('2017-06-17'),
  readingBooks: ['Dream of the Red Chamber']
};

const copied = structuredClone(person);

copied.readingBooks === person.readingBooks

// 循环拷贝
const obj = {a:1}; 
obj.b = obj;
const obj1 = structuredClone(obj);
obj1.b === obj;

// 时间拷贝
const obj = {date: new Date()}
const obj1 = structuredClone(obj);
obj1;
typeof obj1.date

// 特殊值拷贝
const obj = {
    set: new Set([1,2,3]),
    map: new Map([[2,2]]),
    reg: new RegExp(/123/),
    error: new Error('123'),
    none: undefined
}
const obj1 = structuredClone(obj);
obj1;

3、 structuredClone 不能做什么

  • 不允许克隆FunctionDOM对象,如果对象中含有,将抛出DATA_CLONE_ERR异常
  • 大部分Error 支持
    • "图片自定义高度" height="" width=""
  • 对象的某些特定参数也不会被保留
    • RegExp 对象的 lastIndex 字段不会被保留
    • 属性描述符,setters 以及 getters(以及其他类似元数据的功能)同样不会被复制。例如,如果一个对象用属性描述符标记为 read-only,它将会被复制为 read-write,因为这是默认的情况下。
    • 原形链上的属性也不会被追踪以及复制

五、对比三种深拷贝方法

  • JSON.parse(JSON.stringify(obj)) 方法使用简单,且兼容性好,如果你要处理的是简单数据类型的深拷贝,该方法可以 hold 住;
  • _.copyDeep 兼容性好,功能强大,对于 Function 类型不会报错,但是缺点是需要注意处理 tree-shaking 否则会有性能损耗;
  • structuredClone 方法是浏览器原生支持的,对于 Function 类型会报错,但最主要的缺点是兼容性问题;

更多相关网站

JS 原生的深拷贝来啦——structuredClone mdn - structuredClone mdn - structuredClone-类型