Window: structuredClone() 方法

Baseline 已广泛支持

此特性已经十分成熟,可在许多设备和浏览器版本上使用。自 2022 年 3 月起,它已在各浏览器中可用。

Window 接口的 structuredClone() 方法使用结构化克隆算法创建一个给定值的深层克隆

该方法还允许将原始值中的可转移对象转移而不是克隆到新对象。转移的对象将从原始对象中分离并附加到新对象;它们在原始对象中不再可访问。

语法

js
structuredClone(value)
structuredClone(value, options)

参数

value

要克隆的对象。这可以是任何可结构化克隆的类型

options 可选

具有以下属性的对象:

transfer

一个可转移对象数组,这些对象将被移动而不是克隆到返回的对象中。

返回值

原始 value深层副本

异常

DataCloneError DOMException

如果输入值的任何部分不可序列化,则抛出此错误。

描述

此函数可用于深层复制 JavaScript 值。它还支持循环引用,如下所示:

js
// Create an object with a value and a circular reference to itself.
const original = { name: "MDN" };
original.itself = original;

// Clone it
const clone = structuredClone(original);

console.assert(clone !== original); // the objects are not the same (not same identity)
console.assert(clone.name === "MDN"); // they do have the same values
console.assert(clone.itself === clone); // and the circular reference is preserved

转移值

(只有)可转移对象可以使用 options 参数的 transfer 属性进行转移,而不是在克隆对象中复制。转移会使原始对象无法使用。

注意: 一个可能有用的场景是在保存数据之前异步验证缓冲区中的某些数据。为了避免缓冲区在数据保存之前被修改,您可以克隆缓冲区并验证该数据。如果您同时转移数据,任何修改原始缓冲区的尝试都将失败,从而防止其被意外滥用。

以下代码展示了如何克隆数组并将其底层资源转移到新对象。返回时,原始的 uInt8Array.buffer 将被清除。

js
// 16MB = 1024 * 1024 * 16
const uInt8Array = Uint8Array.from({ length: 1024 * 1024 * 16 }, (v, i) => i);

const transferred = structuredClone(uInt8Array, {
  transfer: [uInt8Array.buffer],
});
console.log(uInt8Array.byteLength); // 0

您可以克隆任意数量的对象并转移这些对象的任意子集。例如,下面的代码将从传入的值中转移 arrayBuffer1,但不转移 arrayBuffer2

js
const transferred = structuredClone(
  { x: { y: { z: arrayBuffer1, w: arrayBuffer2 } } },
  { transfer: [arrayBuffer1] },
);

示例

克隆对象

在此示例中,我们克隆了一个带有一个成员(数组)的对象。克隆后,对每个对象的更改不会影响另一个对象。

js
const mushrooms1 = {
  amanita: ["muscaria", "virosa"],
};

const mushrooms2 = structuredClone(mushrooms1);

mushrooms2.amanita.push("pantherina");
mushrooms1.amanita.pop();

console.log(mushrooms2.amanita); // ["muscaria", "virosa", "pantherina"]
console.log(mushrooms1.amanita); // ["muscaria"]

转移对象

在此示例中,我们创建一个 ArrayBuffer,然后克隆它是其成员的对象,同时转移缓冲区。我们可以在克隆对象中使用缓冲区,但如果我们尝试使用原始缓冲区,则会引发异常。

js
// Create an ArrayBuffer with a size in bytes
const buffer = new ArrayBuffer(16);

const object1 = {
  buffer,
};

// Clone the object containing the buffer, and transfer it
const object2 = structuredClone(object1, { transfer: [buffer] });

// Create an array from the cloned buffer
const int32View2 = new Int32Array(object2.buffer);
int32View2[0] = 42;
console.log(int32View2[0]);

// Creating an array from the original buffer throws a TypeError
const int32View1 = new Int32Array(object1.buffer);

规范

规范
HTML
# dom-structuredclone

浏览器兼容性

另见