历史搜索

深入探索JavaScript中的structuredClone:现代深拷贝的解密指南

游客2024-08-17 14:33:01
目录文章目录
  1. 1. 使用 JSON.parse(JSON.stringify(obj))
  2. 2. 使用递归
  3. 3. 第三方库,如 lodash 的 _.cloneDeep 方法
  4. 4. 现代深拷贝 structuredClone
  5. 结语

在 JavaScript 中,实现深拷贝的方式有很多种,每种方式都有其优点和缺点。今天介绍一种原生 JavaScript 提供的structuredClone实现深拷贝。

下面列举一些常见的方式,以及它们的代码示例和优缺点:

1. 使用 JSON.parse(JSON.stringify(obj))

代码示例:

function deepClone(obj) {
    return JSON.parse(JSON.stringify(obj));
}

优点:简单易行,对于大多数对象类型有效。

缺点:不能复制原型链,对于包含循环引用的对象可能出现问题。比如以下代码:

const calendarEvent = {
  date: new Date()
}

const problematicCopy = JSON.parse(JSON.stringify(calendarEvent))

最终得到的 date 不是 Data 对象,而是字符串。

{
    "date": "2024-03-02T03:43:35.890Z"
}

这是因为JSON.stringify只能处理基本的对象、数组。任何其他类型都没有按预期处理。例如,日期转换为字符串。Set/Map 只是转换为{}

const kitchenSink = {
  set: new Set([1, 3, 3]),
  map: new Map([[1, 2]]),
  regex: /foo/,
  deep: { array: [ new File(someBlobData, 'file.txt') ] },
  error: new Error('Hello!')
}

const veryProblematicCopy = JSON.parse(JSON.stringify(kitchenSink))

最终得到如下数据:

{
  "set": {},
  "map": {},
  "regex": {},
  "deep": {
    "array": [
      {}
    ]
  },
  "error": {},
}

2. 使用递归

代码示例:

function deepClone(obj) {
    if (obj === null || typeof obj !== 'object') {
        return obj;
    }
    let clone = obj.constructor();
    for (let attr in obj) {
        if (obj.hasOwnProperty(attr)) {
            clone[attr] = this.deepClone(obj[attr]);
        }
    }
    return clone;
}

优点:对于任何类型的对象都有效,包括循环引用。

缺点:对于大型对象可能会消耗大量内存,并可能导致堆栈溢出。

3. 第三方库,如 lodash 的 _.cloneDeep 方法

代码示例:

const _ = require('lodash');
function deepClone(obj) {
    return _.cloneDeep(obj);
}

优点:支持更多类型的对象和库,例如,支持 Proxy 对象。

缺点:会引入依赖导致项目体积增大。

深入探索JavaScript中的structuredClone:现代深拷贝的解密指南 1

结语

我们现在终于可以直接使用原生 JavaScript 中的structuredClone能力实现深度拷贝对象。每种方式都有其优缺点,具体使用方式取决于你的需求和目标对象的类型。

标签:JSON.parse()