Window:structuredClone() 方法

Baseline Widely available

This feature is well established and works across many devices and browser versions. It’s been available across browsers since March 2022.

Window 接口的 structuredClone() 方法使用结构化克隆算法将给定的值进行深拷贝

该方法还支持把原值中的可转移对象转移(而不是拷贝)到新对象上。可转移对象与原始对象分离并附加到新对象;它们将无法在原始对象中被访问。

语法

js
structuredClone(value)
structuredClone(value, options)

参数

value

被克隆的对象。可以是任何结构化克隆支持的类型

options 可选

一个具有以下属性的对象:

transfer

一个可转移对象的数组,里面的对象将被移动而不是克隆到返回的对象上。

返回值

原始值(value)的深拷贝

异常

DataCloneError DOMException

如果输入值的任一部分不可序列化,则抛出该异常。

描述

这个函数可以用来进行深拷贝 JavaScript 变量。也支持循环引用,如下所示:

js
// 创建一个具有值和对自身的循环引用的对象。
const original = { name: "MDN" };
original.itself = original;

// 对它进行克隆
const clone = structuredClone(original);

console.assert(clone !== original); // 对象并不相同(标识不同)
console.assert(clone.name === "MDN"); // 它们具有相同的值
console.assert(clone.itself === clone); // 且保留了循环引用

转移值

使用参数 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 然后克隆将它作为属性的对象,将它转移。我们可以使用克隆对象里的缓冲区(buffer),但是如果我们尝试使用原对象的缓冲区的话就会产生异常。

js
// 创建一个给定字节大小的 ArrayBuffer
const buffer1 = new ArrayBuffer(16);

const object1 = {
  buffer: buffer1,
};

// 克隆包含 buffer 的对象,并将其转移
const object2 = structuredClone(object1, { transfer: [buffer1] });

// 从克隆后的 buffer 创建数组
const int32View2 = new Int32Array(object2.buffer);
int32View2[0] = 42;
console.log(int32View2[0]);

// 从原 buffer 创建数组将抛出 TypeError
const int32View1 = new Int32Array(object1.buffer);

规范

Specification
HTML
# dom-structuredclone

浏览器兼容性

Report problems with this compatibility data on GitHub
desktopmobileserver
Chrome
Edge
Firefox
Opera
Safari
Chrome Android
Firefox for Android
Opera Android
Safari on iOS
Samsung Internet
WebView Android
WebView on iOS
Deno
Node.js
structuredClone

Legend

Tip: you can click/tap on a cell for more information.

Full support
Full support
Partial support
Partial support
See implementation notes.
Has more compatibility info.

参见