Tags: JavaScript

Jakie są najbardziej wydajne sposoby głębokiego klonowania obiektów w JavaScript?

Głębokie klonowanie obiektów w JavaScript oznacza tworzenie całkowicie nowego obiektu, który jest identyczną kopią oryginału, ale nie ma żadnych odniesień do obiektów zawartych w oryginalnym obiekcie. Oto kilka wydajnych sposobów na głębokie klonowanie:

Użycie JSON.stringify i JSON.parse

Najprostszym (choć nie zawsze najbardziej wydajnym) sposobem na głębokie klonowanie obiektów jest użycie kombinacji `JSON.stringify()` do konwersji obiektu na ciąg JSON, a następnie `JSON.parse()` do przekształcenia tego ciągu z powrotem na nowy obiekt JavaScript.

function deepClone(obj) {
return JSON.parse(JSON.stringify(obj));
}

Wada: Nie obsługuje funkcji, `Map`, `Set`, `RegExp`, `Date` i innych niestandardowych obiektów lub referencji cyklicznych.

Rekurencyjna Funkcja

Możesz napisać funkcję, która rekurencyjnie przechodzi przez wszystkie właściwości obiektu i kopiuje je do nowego obiektu.

function deepClone(obj, hash = new WeakMap()) {
if (obj === null) return null;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
if (typeof obj !== 'object') return obj;
if (hash.has(obj)) return hash.get(obj); // obsługa referencji cyklicznych

const result = Array.isArray(obj) ? [] : {};
hash.set(obj, result);

for (const key in obj) {
if (obj.hasOwnProperty(key)) {
result[key] = deepClone(obj[key], hash);
}
}

return result;
}

Wada: Może być mniej wydajna dla bardzo dużych lub złożonych obiektów.

Biblioteki Klonujące

Istnieje wiele bibliotek, które oferują wydajne i niezawodne funkcje do głębokiego klonowania, np. Lodash z metodą `_.cloneDeep(obj)`.

// Użycie Lodash
var cloned = _.cloneDeep(original);

Zaleta: Lodash i podobne biblioteki są optymalizowane dla różnych przypadków i mogą obsługiwać różnorodne typy danych.

Structured Clone Algorithm

W nowoczesnych przeglądarkach dostępna jest metoda `structuredClone()`, która umożliwia głębokie klonowanie obiektów.

const cloned = structuredClone(original);

Zaleta: Jest to natywna metoda przeglądarki, która jest bardzo wydajna i obsługuje wiele typów danych, w tym `Map`, `Set`, `ArrayBuffer`, `DataView`, `TypedArray`, `ImageBitmap`, `RegExp`, `Date` i niemal wszystko inne, co jest strukturalnie klonowalne.

MessageChannel

Metoda `MessageChannel` może być użyta do głębokiego klonowania poprzez asynchroniczne wysłanie obiektu przez kanał i natychmiastowe jego odebranie.

function deepClone(obj) {
return new Promise(resolve => {
const { port1, port2 } = new MessageChannel();
port2.onmessage = ev => resolve(ev.data);
port1.postMessage(obj);
});
}

Zaleta: Może być szybsza niż JSON dla dużych obiektów, ale nadal jest to rozwiązanie asynchroniczne.

Wybór metody zależy od kontekstu i wymagań. Jeśli obiekt jest prosty i nie zawiera specjalnych typów lub referencji cyklicznych, `JSON` może być wystarczający i łatwy w użyciu. Jeśli jednak potrzebujesz bardziej kompleksowego rozwiązania, `structuredClone`, biblioteki zewnętrzne lub wł