最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JS原生深拷貝的終極方案structuredClone用法代碼示例

 更新時(shí)間:2026年05月27日 11:39:40   作者:代碼里的小貓咪  
structuredClone()是JavaScript中用于創(chuàng)建對象深拷貝的原生方法,相比JSON.parse等傳統(tǒng)方法,它能更全面地處理復(fù)雜數(shù)據(jù)類型,這篇文章主要介紹了JS原生深拷貝的終極方案structuredClone用法的相關(guān)資料,需要的朋友可以參考下

前言

在 JavaScript 開發(fā)中,對象的深拷貝一直是一個(gè)經(jīng)典痛點(diǎn)。從 JSON.parse(JSON.stringify()) 的 hack,到 Lodash 的 _.cloneDeep(),開發(fā)者們一直在找一個(gè)既可靠又高效的深拷貝。2022 年,structuredClone 作為全局 API 正式進(jìn)入所有主流瀏覽器和 Node.js,終結(jié)了這場漫長的探索。

1. 基本用法

const original = {
  name: 'Alice',
  scores: [95, 87, 92],
  metadata: {
    createdAt: new Date(),
    pattern: /hello/gi,
  },
};

const cloned = structuredClone(original);

cloned.scores.push(100);
console.log(original.scores); // [95, 87, 92] — 互不影響
console.log(cloned.metadata.createdAt instanceof Date); // true — 類型保留
console.log(cloned.metadata.pattern instanceof RegExp); // true

一行代碼,深拷貝完成。沒有序列化/反序列化的中間步驟,沒有第三方依賴。

Transfer 參數(shù)

structuredClone 的第二個(gè)參數(shù)支持 transfer 選項(xiàng),這是它相比其他深拷貝方案的獨(dú)特能力:

const buffer = new ArrayBuffer(1024 * 1024 * 100); // 100MB

// 傳統(tǒng)克?。簭?fù)制 100MB 內(nèi)存
const cloned = structuredClone(buffer);

// Transfer:所有權(quán)轉(zhuǎn)移,零拷貝
const transferred = structuredClone(buffer, { transfer: [buffer] });

console.log(buffer.byteLength); // 0 
console.log(transferred.byteLength); // 104857600

Transfer 的本質(zhì)是所有權(quán)轉(zhuǎn)移(ownership transfer),不是復(fù)制。底層只是修改了內(nèi)存區(qū)域的歸屬指針,時(shí)間復(fù)雜度 O(1)。

為什么要這樣設(shè)計(jì)?

核心原因是性能。如果要把 100MB 的視頻幀數(shù)據(jù)發(fā)給 Web Worker 處理:

// 方式 1:復(fù)制(慢,瞬間多占 100MB 內(nèi)存)
worker.postMessage(buffer);

// 方式 2:轉(zhuǎn)移(瞬間完成,內(nèi)存不增長)
worker.postMessage(buffer, [buffer]);
// 但此后主線程不能再用這個(gè) buffer 了

Transfer 的代價(jià)是:原始變量變成一個(gè)"空殼"(規(guī)范稱為 detached / neutered)。這是一個(gè)權(quán)衡——用"獨(dú)占訪問權(quán)"換來了"零拷貝性能"。

2. 支持/行為

這是 structuredClone 最大的優(yōu)勢所在。

  • 支持:普通對象、數(shù)組、Date、Map、Set、RegExp、ArrayBuffer、TypedArray、Blob、File、BigInt、循環(huán)引用等
  • 不支持/會報(bào) DataCloneError(典型):
    • function,函數(shù)閉包綁定了執(zhí)行上下文,無法序列化
    • WeakMap/WeakSet,弱引用語義不允許枚舉
    • Proxy(Vue reactive 就在這)
    • DOM Nodes,綁定了渲染樹,跨上下文無意義
  • 保留對象圖結(jié)構(gòu):可保留“同一引用關(guān)系”和循環(huán)結(jié)構(gòu)

關(guān)鍵:原型鏈丟失

class Vector {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
  magnitude() {
    return Math.sqrt(this.x ** 2 + this.y ** 2);
  }
}

const v = new Vector(3, 4);
const cloned = structuredClone(v);

console.log(cloned.x); // 3
console.log(cloned.magnitude); // undefined 
console.log(Object.getPrototypeOf(cloned) === Vector.prototype); // false
console.log(Object.getPrototypeOf(cloned) === Object.prototype); // true

structuredClone 克隆的是數(shù)據(jù),不是行為。

對比 JSON.parse(JSON.stringify()) 支持/行為

  • 支持:普通對象、數(shù)組、字符串、數(shù)字、布爾、null
  • 會丟失/變化:
    • undefined(對象屬性會被丟棄)
    • function(丟棄)
    • symbol(丟棄)
    • Date -> 字符串(ISO)
    • Map/Set -> 通常變空對象或丟信息
    • RegExp -> 普通對象/空對象
    • NaN/Infinity/-Infinity -> null
    • BigInt -> 直接報(bào)錯(cuò)(TypeError)
  • 循環(huán)引用:直接報(bào)錯(cuò) Converting circular structure to JSON

循環(huán)引用

這是 structuredClone 相比 JSON 方案的核心優(yōu)勢之一:

const obj = { name: 'root' };
obj.self = obj;
obj.children = [{ parent: obj }];

// JSON 方案直接爆炸
// JSON.stringify(obj); // TypeError: Converting circular structure to JSON

// structuredClone 優(yōu)雅處理
const cloned = structuredClone(obj);
console.log(cloned.self === cloned); // true
console.log(cloned.children[0].parent === cloned); // true
console.log(cloned !== obj); // true 

算法內(nèi)部維護(hù)了一個(gè) (source, clone) 的映射表。當(dāng)遍歷到已經(jīng)克隆過的對象時(shí),直接返回映射表中的克隆體,從而:

  • 避免無限遞歸
  • 保持引用拓?fù)浣Y(jié)構(gòu)的一致性

3. 底層原理

JSON 方案底層原理

JSON.stringify(ECMAScript JSON 序列化算法)做的事:

  • 遍歷對象可序列化屬性
  • 處理 toJSON(如 Date 會先轉(zhuǎn)字符串)
  • 生成 JSON 文本(UTF-16 JS 字符串)

JSON.parse 做的事:

  • 詞法/語法解析 JSON 文本
  • 構(gòu)建全新 JS 對象樹
  • 可選 reviver 二次轉(zhuǎn)換

本質(zhì):文本協(xié)議往返

structuredClone 底層原理

基于 HTML 標(biāo)準(zhǔn)里的 Structured Clone Algorithm(瀏覽器/運(yùn)行時(shí)實(shí)現(xiàn)):

  • 從源對象圖開始遍歷
  • 維護(hù)“已訪問對象表”(解決循環(huán)與共享引用
  • 按對象類型走不同克隆分支(Map/Set/Date/TypedArray 等)
  • 生成克隆對象圖并重建引用關(guān)系
  • 可選 transfer 列表:對可轉(zhuǎn)移對象“轉(zhuǎn)移所有權(quán)”(原對象 detach)

本質(zhì):對象圖語義復(fù)制(不是文本)。

4. 一句話總結(jié)

1、JSON.parse(JSON.stringify(obj)):本質(zhì)是先序列化成 JSON 文本,再解析回對象,是“文本中轉(zhuǎn)”。

2、structuredClone(obj):本質(zhì)是按結(jié)構(gòu)化克隆算法直接復(fù)制內(nèi)存對象圖,不是 JSON 文本中轉(zhuǎn)。

附:structuredClone () 與其他克隆方法詳細(xì)對比

與 JSON.parse (JSON.stringify ()) 對比

在 JavaScript 中,JSON.parse(JSON.stringify()) 是一種常用的實(shí)現(xiàn)深拷貝的方法,但它與 structuredClone() 存在諸多差異。

在支持的數(shù)據(jù)類型方面,JSON.parse(JSON.stringify()) 僅支持基本數(shù)據(jù)類型(如數(shù)字、字符串、布爾值)、普通對象和數(shù)組 。對于 Date 對象,它會將其轉(zhuǎn)換為字符串,在反序列化后不再是 Date 對象,而是普通字符串;Map、Set、RegExp 對象會被轉(zhuǎn)換為空對象;函數(shù)、undefined、symbol、Infinity、NaN 以及循環(huán)引用等都無法正確處理 。而 structuredClone() 支持的數(shù)據(jù)類型更為廣泛,除了基本數(shù)據(jù)類型和普通對象、數(shù)組外,還支持 Date、RegExp、Map、Set、ArrayBuffer、TypedArrays、Blob、File、ImageData、MessagePort 等,并且能正確處理循環(huán)引用 。例如:

// JSON.parse(JSON.stringify()) 處理不支持的類型
const original1 = {
date: new Date(),
map: new Map([['key1', 'value1']]),
func: function() { return 'function' }
};
const jsonClone1 = JSON.parse(JSON.stringify(original1));
console.log(jsonClone1.date instanceof Date); // false,Date 被轉(zhuǎn)為字符串
console.log(jsonClone1.map instanceof Map); // false,Map 被轉(zhuǎn)為空對象
console.log(jsonClone1.func); // undefined,函數(shù)丟失
// structuredClone() 處理支持的類型
const original2 = {
date: new Date(),
map: new Map([['key1', 'value1']]),
arrayBuffer: new Uint8Array([1, 2, 3]).buffer
};
const structuredClone2 = structuredClone(original2);
console.log(structuredClone2.date instanceof Date); // true
console.log(structuredClone2.map instanceof Map); // true
console.log(structuredClone2.arrayBuffer instanceof ArrayBuffer); // true

在循環(huán)引用處理上,JSON.parse(JSON.stringify()) 無法處理對象中的循環(huán)引用,當(dāng)對象存在循環(huán)引用時(shí),調(diào)用 JSON.stringify() 會拋出 TypeError: Converting circular structure to JSON 錯(cuò)誤 ,導(dǎo)致克隆失敗。而 structuredClone() 可以正確處理循環(huán)引用,確保克隆后的對象包含正確的循環(huán)引用結(jié)構(gòu),不會陷入無限循環(huán) 。比如:

// JSON.parse(JSON.stringify()) 處理循環(huán)引用
let obj1 = {};
let obj2 = { ref: obj1 };
obj1.ref = obj2;
try {
const jsonClone = JSON.parse(JSON.stringify(obj1));
} catch (error) {
console.error('JSON.parse(JSON.stringify())循環(huán)引用錯(cuò)誤:', error); // 拋出錯(cuò)誤
}
// structuredClone() 處理循環(huán)引用
let obj3 = {};
let obj4 = { ref: obj3 };
obj3.ref = obj4;
const structuredClone3 = structuredClone(obj3);
console.log(structuredClone3.ref === structuredClone3.ref.ref); // true,循環(huán)引用處理正確

性能方面,JSON.parse(JSON.stringify()) 在處理簡單的、JSON 兼容的數(shù)據(jù)結(jié)構(gòu)時(shí)性能尚可,但在處理復(fù)雜對象或包含大量非 JSON 兼容類型的數(shù)據(jù)時(shí),由于需要進(jìn)行序列化和反序列化操作,效率較低 。structuredClone() 是為深度克隆設(shè)計(jì)的原生方法,內(nèi)部針對復(fù)雜場景進(jìn)行了優(yōu)化,通常在處理復(fù)雜對象時(shí)性能更優(yōu) 。通過以下測試可以明顯看出兩者的性能差異:

// 性能測試
const largeArray = new Array(10000).fill({ key: 'value' });
console.time('JSON.parse(JSON.stringify())');
const jsonClone = JSON.parse(JSON.stringify(largeArray));
console.timeEnd('JSON.parse(JSON.stringify())');
console.time('structuredClone');
const structuredClone4 = structuredClone(largeArray);
console.timeEnd('structuredClone');

在瀏覽器兼容性上,JSON.parse(JSON.stringify()) 在現(xiàn)代瀏覽器和較舊的瀏覽器中都有廣泛支持 。而 structuredClone() 是一種較新的 API,在某些較舊的瀏覽器中不被支持 ,使用時(shí)需要考慮兼容性問題,可以通過檢測 typeof structuredClone === 'function' 來判斷瀏覽器是否支持該方法,不支持時(shí)可采用其他替代方案。

到此這篇關(guān)于JS原生深拷貝的終極方案structuredClone用法代碼示例的文章就介紹到這了,更多相關(guān)JS原生深拷貝structuredClone內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 通過js控制修改css變量的具體示例

    通過js控制修改css變量的具體示例

    在網(wǎng)頁開發(fā)中我們通常使用CSS來設(shè)置網(wǎng)頁的樣式,但是,在開發(fā)過程中,有時(shí)候我們需要根據(jù)不同的條件來動(dòng)態(tài)修改樣式,這篇文章主要介紹了通過js控制修改css變量的具體示例,需要的朋友可以參考下
    2025-04-04
  • es7中的async、await使用方法示例詳解

    es7中的async、await使用方法示例詳解

    async、await是es7里面的新語法,async申明一個(gè)function是異步,而await等待一個(gè)異步方法執(zhí)行完成。替代promise中的then。async函數(shù)返回一個(gè)Promise對象,當(dāng)函數(shù)執(zhí)行的時(shí)候,一旦遇到await就會先返回,等到觸發(fā)的異步操作完成,再接著執(zhí)行函數(shù)體內(nèi)后面的語句。
    2023-01-01
  • javascript基于prototype實(shí)現(xiàn)類似OOP繼承的方法

    javascript基于prototype實(shí)現(xiàn)類似OOP繼承的方法

    這篇文章主要介紹了javascript基于prototype實(shí)現(xiàn)類似OOP繼承的方法,實(shí)例分析了JavaScript使用prototype實(shí)現(xiàn)面向?qū)ο蟪绦蛟O(shè)計(jì)的中類繼承的相關(guān)技巧,需要的朋友可以參考下
    2015-12-12
  • 微信小程序?qū)崿F(xiàn)通過雙向滑動(dòng)縮放圖片大小的方法

    微信小程序?qū)崿F(xiàn)通過雙向滑動(dòng)縮放圖片大小的方法

    這篇文章主要介紹了微信小程序?qū)崿F(xiàn)通過雙向滑動(dòng)縮放圖片大小的方法,結(jié)合實(shí)例形式分析了微信小程序事件響應(yīng)及圖片元素屬性動(dòng)態(tài)操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2018-12-12
  • BootStrap表單控件之文本域textarea

    BootStrap表單控件之文本域textarea

    這篇文章主要介紹了BootStrap表單控件之文本域textarea,需要的朋友可以參考下
    2017-05-05
  • javascript實(shí)現(xiàn)自由編輯圖片代碼詳解

    javascript實(shí)現(xiàn)自由編輯圖片代碼詳解

    這篇文章主要介紹了javascript實(shí)現(xiàn)自由編輯圖片代碼詳解,在當(dāng)下的的前端項(xiàng)目中,圖片功能可以說是非常常見的,圖片的展示、圖片的裁剪編輯、圖片的上傳等,那么我們的項(xiàng)目便來了個(gè)需求。,需要的朋友可以參考下
    2019-06-06
  • JavaScript列表框listbox全選和反選的實(shí)現(xiàn)方法

    JavaScript列表框listbox全選和反選的實(shí)現(xiàn)方法

    這篇文章主要介紹了JavaScript列表框listbox全選和反選的實(shí)現(xiàn)方法,涉及javascript操作列表框listbox的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2015-03-03
  • JavaScript定義和初始化二維數(shù)組的三種常用方法

    JavaScript定義和初始化二維數(shù)組的三種常用方法

    這篇文章主要介紹了在 JavaScript 中定義和初始化二維數(shù)組的三種常用方法,并通過示例代碼和實(shí)際應(yīng)用場景進(jìn)行解釋,幫助開發(fā)者深入理解其使用技巧和注意事項(xiàng),需要的朋友可以參考下
    2025-12-12
  • JS DOM 操作實(shí)現(xiàn)代碼

    JS DOM 操作實(shí)現(xiàn)代碼

    JS DOM 操作實(shí)現(xiàn)代碼,學(xué)習(xí)dom操作的朋友可以參考下。
    2010-08-08
  • js實(shí)現(xiàn)拖拽上傳圖片功能

    js實(shí)現(xiàn)拖拽上傳圖片功能

    這篇文章主要為大家詳細(xì)介紹了js實(shí)現(xiàn)拖拽上傳圖片功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-08-08

最新評論

海林市| 沙田区| 沂南县| 晋州市| 璧山县| 盘山县| 台州市| 长沙县| 安西县| 商水县| 钦州市| 康乐县| 常熟市| 古交市| 克东县| 淮南市| 岳西县| 龙门县| 长白| 内黄县| 普宁市| 深州市| 斗六市| 沛县| 岳西县| 剑川县| 陇南市| 南乐县| 雷山县| 抚松县| 和平县| 舟曲县| 兰溪市| 三台县| 沛县| 濮阳市| 全州县| 华亭县| 浦城县| 湘阴县| 望谟县|