總結
幾個主流瀏覽器與 Node.js 17.0.0 版開始支援 JS 原生的深拷貝功能 structuredClone(),此篇文章會記錄一下本功能的使用方式。
支援環境
Chrome: 98Edge: 98FireFox: 94Safari: 15.4Node.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 workconst int32View2 = new Int32Array(obj2.buffer);// this will throw TypeErrorconst int32View1 = new Int32Array(obj1.buffer);說明:obj1.buffer 具有 transferable 特性,透過 structuredClone(obj1, { transfer: [obj1.buffer] }) 後,此 .buffer 從原本的 obj1 被移動到 obj2 中。物件 obj1.buffer 被清空後,想透過 new Int32Array() 建立實例會導致失敗拋錯。