這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助
你是否知道,JavaScript中有一種原生的方法來做物件的深拷貝?
本文我們要介紹的是 structuredClone 函式,它是內置在 JavaScript 運行時中的:
const calendarEvent = {
title: "前端修羅場",
date: new Date(123),
attendees: ["Steve"]
}
const copied = structuredClone(calendarEvent)
在上面的示例中,我們不僅拷貝了物件,還拷貝了嵌套陣列,甚至拷貝了Date 物件:
copied.attendees // ["Steve"] copied.date // Date: Wed Dec 31 1969 16:00:00 cocalendarEvent.attendees === copied.attendees // false
沒錯,structuredClone 不僅可以做到以上這些,而且還可以:
- 克隆無限嵌套的物件和陣列
- 克隆回圈參考
- 克隆各種各樣的 JavaScript 型別,如
Date, Set, Map, Error, RegExp, ArrayBuffer, Blob, File, ImageData等等 - 轉移任何可轉移的物件
舉個例子:
const kitchenSink = {
set: new Set([1, 3, 3]),
map: new Map([[1, 2]]),
regex: /foo/,
deep: { array: [ new File(someBlobData, 'file.txt') ] },
error: new Error('Hello!')
}
kitchenSink.circular = kitchenSink
// 以上都會被克隆
const clonedSink = structuredClone(kitchenSink)
為什么不使用物件擴展運算子進行克隆呢
值得注意的是,我們討論的是深拷貝,如果你只需要做一個淺拷貝,也就是一個不復制嵌套物件或陣列的拷貝,那么我們可以只做一個物件擴展:
const simpleEvent = {
title: "前端修羅場",
}
const shallowCopy = {...calendarEvent}
或者你也可以使用這種方法:
const shallowCopy = Object.assign({}, simpleEvent)
const shallowCopy = Object.create(simpleEvent)
但是一旦我們有了嵌套項,我們就會遇到麻煩:
const calendarEvent = {
title: "前端修羅場",
date: new Date(123),
attendees: ["Steve"]
}
const shallowCopy = {...calendarEvent}
shallowCopy.attendees.push("Bob")
shallowCopy.date.setTime(456)
如上所見,我們沒有對該物件進行完整復制,
嵌套日期和陣列仍然是兩者之間的共享參考,如果我們想編輯它們,認為我們只是更新復制的日歷事件物件,這可能會導致重大問題,
為什么不使用JSON.parse(JSON.stringify(x)) ?
它實際上是一個很棒的工具,性能令人驚訝,但也有一些structuredClone可以解決的缺點,
舉個例子:
const calendarEvent = {
title: "前端修羅場",
date: new Date(123),
attendees: ["Steve"]
}
const problematicCopy = JSON.parse(JSON.stringify(calendarEvent))
如果我們輸出 problematicopy,我們會得到:
{
title: "前端修羅場",
date: "1970-01-01T00:00:00.123Z"
attendees: ["Steve"]
}
這不是我們想要的 date 格式,因為格式應該是date物件,而不是字串,
這是因為 JSON.Stringify 只能處理基本物件、陣列和基本型別,任何其他型別都可能以難以預測的方式處理,例如,日期被轉換為字串,但是 Set 物件就會被簡單地轉換為 {},
同時,JSON.Stringify 甚至會完全忽略某些東西,如 undefined 或 function,
例如,如果我們用這個方法復制下面這個例子:
const kitchenSink = {
set: new Set([1, 3, 3]),
map: new Map([[1, 2]]),
regex: /foo/,
deep: { array: [ new File(someBlobData, 'file.txt') ] },
error: new Error('Hello!')
}
const veryProblematicCopy = JSON.parse(JSON.stringify(kitchenSink))
輸出之后,得到的是這樣:
{
"set": {},
"map": {},
"regex": {},
"deep": {
"array": [
{}
]
},
"error": {},
}
可以看到, 這種方法的拷貝出錯了,
因此,如果我們的需求適合這個方法,可以用這個方法,但是,我們可以用 structuredClone 做這個方法有很多不能做的事情,
為什么不是 _.cloneDeep?
到目前為止,Lodash 的 cloneDeep 函式是這個問題的一個非常常見的解決方案,事實上,這確實也像預期的那樣作業:
import cloneDeep from 'lodash/cloneDeep'
const calendarEvent = {
title: "前端修羅場",
date: new Date(123),
attendees: ["Steve"]
}
// ?
const clonedEvent = structuredClone(calendarEvent)
但是,這里有一個警告,根據我的 IDE 中的匯入成本擴展,列印任何我匯入函式的成本,這個函式占了 17.4kb` 的大小(5.3kb gzip):
假設你只匯入了這個函式,如果改用更常見的方式匯入,沒有意識到搖樹并不總是按希望的方式作業,那么可能會無意中為這個函式匯入高達2 5kb 的檔案??
什么是 structuredClone 克隆不了的
函式不能被克隆
structuredClone({ fn: () => { } }) // 會拋出一個 DataCloneError 例外
DOM 節點不能克隆
structuredClone({ el: document.body })// 會拋出一個 DataCloneError 例外
屬性描述符 setter和getter 不能克隆
類似元資料的特性也不會被克隆,
例如,使用 getter,結果值會被克隆,但不會克隆 getter 函式本身(或任何其他屬性元資料):
structuredClone({ get foo() { return 'bar' } })
// log: { foo: 'bar' }
物件屬性不能被克隆
原型鏈不會被遍歷或復制,因此,如果克隆MyClass的一個實體,克隆的物件將不再是該類的實體(但該類的所有有效屬性將被克隆)
class MyClass {
foo = 'bar'
myMethod() { /* ... */ }
}
const myClass = new MyClass()
const cloned = structuredClone(myClass)
// log: { foo: 'bar' }
cloned instanceof myClass // false
structuredClone 支持型別的完整串列
更簡單地說,任何不在下面串列中的東西都不能克隆:
-
JS 內置型別:
Array, ArrayBuffer, Boolean, DataView, Date, Error types (those specifically listed below), Map , Object but only plain objects (e.g. from object literals), Primitive types, except symbol (aka number, string, null, undefined, boolean, BigInt), RegExp, Set, TypedArray -
Error types:
Error, EvalError, RangeError, ReferenceError , SyntaxError, TypeError, URIError -
Web/API types:
AudioData, Blob, CryptoKey, DOMException, DOMMatrix, DOMMatrixReadOnly, DOMPoint, DomQuad, DomRect, File, FileList, FileSystemDirectoryHandle, FileSystemFileHandle, FileSystemHandle, ImageBitmap, ImageData, RTCCertificate, VideoFrame
瀏覽器支持
所有主流瀏覽器都支持 structuredClone,甚至Node.js和Deno,
不過在 Web worker 中,目前支持是比較有限的,
本文轉載于:
https://juejin.cn/post/7209226686372692029
如果對您有所幫助,歡迎您點個關注,我會定時更新技術檔案,大家一起討論學習,一起進步,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/547114.html
標籤:其他
上一篇:vue-router的兩種模式
下一篇:Vue框架快速上手

