JavaScript 原生深拷貝功能:structuredClone
總結
幾個主流瀏覽器與 Node.js 17.0.0 版開始支援 JS 原生的深拷貝功能 structuredClone(),此篇文章會記錄一下本功能的使用方式。
支援環境
Chrome: 98
Edge: 98
FireFox: 94
Safari: 15.4
Node.js: 17.0.0
筆記
基本功能
把要深拷貝的對象做為參數傳入 structuredClone() 中,取得的回傳內容即是經過深拷貝的新物件。
const obj1 = {
fruit: ['apple', 'banana', 'cherry'],
vegetable: ['broccoli', 'carrot'],
};
const obj2 = structuredClone(obj1);
obj1.vegetable.push('garlic');
console.info(obj1);
/*
{
fruit: ['apple', 'banana', 'cherry'],
vegetable: ['broccoli', 'carrot', 'garlic'],
}
*/
console.info(obj2);
/*
{
fruit: ['apple', 'banana', 'cherry'],
vegetable: ['broccoli', 'carrot'],
}
*/
如果沒有執行深拷貝,則上述 obj1.vegetable.push(...) 會一併影響到 obj2.vegetable 的內容,因為 obj1.vegetable 與 obj2.vegetable 實際還是指向記憶體中的同一個區塊。展示如下:
const obj1 = {
fruit: ['apple', 'banana', 'cherry'],
vegetable: ['broccoli', 'carrot'],
};
const obj2 = { ...obj1 };
obj1.vegetable.push('garlic');
console.info(obj1);
/*
{
fruit: ['apple', 'banana', 'cherry'],
vegetable: ['broccoli', 'carrot', 'garlic'],
}
*/
console.info(obj2);
/*
{
fruit: ['apple', 'banana', 'cherry'],
vegetable: ['broccoli', 'carrot', 'garlic'],
}
*/
搬移功能
擁有 transferable 特性的物件(參考 MDN 的 一覽表)可以透過 structuredClone() 來執行「搬移」。
語法:在 structuredClone() 的第二個參數傳入物件 { transfer: [...] } ,並在陣列中指定搬移對象。
const buff = new ArrayBuffer(16);
const obj1 = { buffer: buff };
const obj2 = structuredClone(obj1, { transfer: [obj1.buffer] });
console.info(obj1);
// { "buffer": ArrayBuffer(0) }
console.info(obj2);
// { "buffer": ArrayBuffer(16) }
// this will work
const int32View2 = new Int32Array(obj2.buffer);
// this will throw TypeError
const int32View1 = new Int32Array(obj1.buffer);
說明:obj1.buffer 具有 transferable 特性,透過 structuredClone(obj1, { transfer: [obj1.buffer] }) 後,此 .buffer 從原本的 obj1 被移動到 obj2 中。物件 obj1.buffer 被清空後,想透過 new Int32Array() 建立實例會導致失敗拋錯。