结构化克隆API的前世今生:从深拷贝到原生力量structuredClone()


引言:结构化克隆API的前世今生:从深拷贝到原生力量

在JavaScript的世界里,数据复制是一个常见的需求。尤其是对于复杂的数据结构,如嵌套对象和数组,浅拷贝与深拷贝的概念显得尤为重要。随着技术的发展,我们拥有了structuredClone() API这一强大的内置工具,它不仅解决了深拷贝的问题,还提供了高效的处理机制。本文将通过探讨深浅拷贝概念、手写一个完整的深拷贝方法,并详细解读structuredClone() API的工作原理及其实现,带你走进这个功能强大的API的前世今生。

一、深拷贝与浅拷贝

1. 浅拷贝(Shallow Copy)
浅拷贝是指创建一个新的对象或数组,其元素与原始对象或数组的引用相同,但不包含嵌套对象或数组的独立副本。例如:

let obj = { a: 1, b: { c: 2 } };
let shallowCopy = Object.assign({}, obj);

obj.b.c = 3;
console.log(shallowCopy); // 输出:{ a: 1, b: { c: 3 } }

在这个例子中,虽然shallowCopy是新创建的对象,但是它的b属性指向了与obj.b相同的内存地址,因此当修改obj.b.c时,shallowCopy也会受到影响。

2. 深拷贝(Deep Copy)
深拷贝则是创建一个与原始对象完全独立且内容一致的新对象,包括所有嵌套的对象和数组。这要求递归地复制所有层级的数据。

二、手写一个功能齐全的深拷贝函数

下面是一个简单的深拷贝函数实现,它可以处理基本类型、数组、对象以及它们的嵌套结构:

function deepClone(obj) {
  if (obj === null) return null;
  let cloneObj;
  
  if (Array.isArray(obj)) {
    cloneObj = [];
    for (let i = 0; i < obj.length; i++) {
      cloneObj[i] = deepClone(obj[i]);
    }
  } else if (typeof obj === 'object') {
    cloneObj = {};
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        cloneObj[key] = deepClone(obj[key]);
      }
    }
  } else {
    // 处理基本类型
    return obj;
  }
  
  return cloneObj;
}

let obj = { a: 1, b: { c: 2 } };
let deepCopiedObj = deepClone(obj);

obj.b.c = 3;
console.log(deepCopiedObj); // 输出:{ a: 1, b: { c: 2 } }

三、structuredClone API 的详细解读

structuredClone() 出场

在ECMAScript 6规范之后,Web浏览器引入了一个原生的API——structuredClone(),专门用于深度克隆复杂的数据结构,包括那些自定义类实例无法通过手写方法完美复制的情况。

structuredClone() 是JavaScript中的一个原生API,用于创建给定值的深层拷贝(深克隆)。这个方法使用结构化克隆算法(Structured Clone Algorithm),能够处理包括数组、对象以及一些内置类型在内的复杂数据结构,并且能够正确地复制它们的所有嵌套属性和循环引用。

结构化克隆算法概述

结构化克隆算法可以递归地遍历并复制以下类型的值:

  • 基本类型:如数字、字符串、布尔值
  • null
  • undefined
  • Date 对象
  • RegExp 对象
  • ArrayBuffer, DataView, Int8Array, Uint8Array 等 TypedArray 类型
  • Map 和 Set 对象及其内容
  • 函数对象以外的普通对象及其可枚举属性(不包括原型链)
  • Promise 对象
  • Symbol 类型
  • 循环引用的对象结构

使用方式

let originalObject = { a: 1, b: { c: 2 } };
let clonedObject = structuredClone(originalObject);

// 修改克隆后的对象不会影响原始对象
clonedObject.a = 2;
clonedObject.b.c = 3;

console.log(originalObject); // 输出:{ a: 1, b: { c: 2 } }
console.log(clonedObject);   // 输出:{ a: 2, b: { c: 3 } }

功能特点

  • 深度拷贝:与浅拷贝不同,structuredClone() 不仅复制对象的第一层属性,还会递归复制所有嵌套的对象和数组,确保整个数据结构独立于原始对象。
  • 处理循环引用:该算法能识别并正确处理循环引用的情况,即对象之间相互引用的情况。
  • 性能优化:在实现过程中,算法会维护一个内部映射表以避免对同一对象的重复复制,从而提高效率。

应用场景

structuredClone() 在实际开发中有多种用途,例如:

  • 在Web Workers中传递复杂的数据结构。
  • 将数据持久化存储到IndexedDB中。
  • 创建对象的副本以防止直接修改原有数据。

注意事项

尽管功能强大,但structuredClone()仍有一些限制:

  • 它不能复制函数、正则表达式实例的 lastIndex 属性、Symbol描述符以及其他不可序列化的内部属性。
  • 对于自定义类的实例或包含不可序列化属性的对象,该方法可能无法完全克隆其状态。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
在Java中,可以使用序列来实现拷贝拷贝是指创建一个全新的对象,将原始对象的所有属性值复制到新对象中。以下是一个简单的示例代码,演示如何通过序列实现拷贝: ```java import java.io.*; class MyClass implements Serializable { private int value; public MyClass(int value) { this.value = value; } public int getValue() { return value; } } public class DeepCopyExample { public static void main(String[] args) throws IOException, ClassNotFoundException { // 创建原始对象 MyClass originalObj = new MyClass(10); // 将原始对象序列到字节数组输出流中 ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(originalObj); oos.close(); // 从字节数组输入流中反序列出新的对象 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); MyClass clonedObj = (MyClass) ois.readObject(); ois.close(); // 修改原始对象的值 originalObj.setValue(20); // 输出结果 System.out.println("Original value: " + originalObj.getValue()); System.out.println("Cloned value: " + clonedObj.getValue()); } } ``` 在上面的示例中,我们定义了一个名为`MyClass`的类,它实现了`Serializable`接口。然后,我们创建了一个原始对象`originalObj`,并将其序列到字节数组输出流中。接着,我们通过反序列从字节数组输入流中创建了一个新的对象`clonedObj`。最后,我们修改了原始对象的值,并输出了原始对象和克隆对象的值。 通过这种方式,我们实现了拷贝,因为`clonedObj`是一个全新的对象,它的属性值与原始对象`originalObj`的属性值相同,但是它们之间没有引用关系。这意味着对其中一个对象的修改不会影响另一个对象。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

球球不吃虾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值