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()
建立實例會導致失敗拋錯。