Klonování polí v JavaScriptu

V jednom z mých předchozích článků jsem se zabýval tím, jak můžete kopírovat objekty v JavaScriptu. Kopírování objektu je poměrně komplikované, vzhledem k tomu, že byste také museli být schopni zkopírovat každý jiný datový typ, který by mohl být v objektu. Ale co když jste jen kopírování pole? Stejně jako v předchozím článku existuje několik způsobů, jak tento úkol provést, z nichž některé v tomto článku proberu.

Nejprve ale poznámka k rychlosti. I když to nemusí být důležité pro všechny aplikace, je třeba zvážit, zda je kopírování velkých polí běžnou operací ve vašem kódu, nebo jestli opravdu záleží na rychlosti. U některých níže uvedených metod zaznamenávám jejich rychlost vzhledem k ostatním metodám, která vychází z výsledků tohoto benchmarku.

Kopírování jednoduchých polí

Pro tuto první část předpokládejme, že pole, které chcete kopírovat, obsahuje pouze primitivní (a neměnné) datové typy. To znamená, že pole obsahuje pouze čísla, booleany, řetězce atd. Můžeme se tak více zaměřit na přenos dat z jednoho pole do druhého, na rozdíl od toho, jak si poradíme s kopírováním skutečného obsahu pole, což uvedu obálku v části „Hluboké kopie“ níže.

Existuje překvapivý počet způsobů, jak zkopírovat pole, některé z nich zahrnují:

  • push
  • Šířit
  • slice
  • Array.from
  • _.clone

Operátor šíření a slice metoda jsou nejrychlejší způsoby, jak zkopírovat mělké pole, ale mějte na paměti, že to závisí na základním běhovém prostředí, takže to nemusí být univerzálně pravdivé.

Push

Toto je pravděpodobně nejzřejmější řešení, které prochází přes původní pole a používá push() nového pole metoda pro přidání prvků z jednoho pole do druhého:

let oldArr = [3, 1, 5, 2, 9];
let newArr = [];
for (let i=0; i < oldArr.length; i++) {
    newArr.push(oldArr[i]);
}

Jednoduše provedeme smyčku přes pole, které se má zkopírovat, a přesuneme každý prvek do nového pole.

Šíření

Tato metoda využívá operátor spread, který byl definován v ES6 a je dostupný ve většině aktuálních prohlížečů.

Funguje to takto:

let oldArr = [3, 1, 5, 2, 9];
let newArr = [...oldArr];

Pokud budu používat nativní řešení a žádnou knihovnu třetí strany, pak toto je obvykle řešení, které preferuji díky jeho čisté a jednoduché syntaxi.

Jedna důležitá poznámka je, že toto kopírování funguje pouze na nejvyšší úrovni (jako mnoho z těchto metod), takže by se nemělo používat, pokud potřebujete hluboké kopie čehokoli.

Plátek

slice() metoda se obvykle používá pro vrácení části pole, zadané pomocí beginning a end parametry. Pokud však nejsou předány žádné parametry, je vrácena kopie celého pole:

let oldArr = [3, 1, 5, 2, 9];
let newArr = oldArr.slice();

V mnoha běhových prostředích JavaScriptu je to nejrychlejší způsob, jak zkopírovat pole.

Pole.from

Array.from metoda je určena k vytvoření mělké kopie jakékoli iterovatelné předáte mu a jako druhý parametr také vezme volitelnou mapovací funkci. Lze jej tedy použít k vytvoření pole z řetězců, množin, map a samozřejmě dalších polí:

let oldArr = [3, 1, 5, 2, 9];
let newArr = Array.from(oldArr);

Klon Lodash

Lodashovy metody clone() a cloneDeep() vám mohou být známé, pokud si přečtete tento článek o kopírování objektů. Metody dělají přesně to, co byste očekávali – jakýkoli objekt (nebo pole, primitiv atd.) předaný do něj bude zkopírován a vrácen.

_.cloneDeep (popsáno dále níže) se liší v tom, že nezastaví klonování na nejvyšší úrovni, bude rekurzivně kopírovat všechny objekty, na které narazí na jakékoli úrovni.

Vzhledem k tomu jej můžeme použít také ke kopírování polí:

let oldArr = [3, 1, 5, 2, 9];
let newArr = _.clone(oldArr);

_.clone funguje velmi dobře ve srovnání s ostatními metodami, takže pokud již tuto knihovnu ve své aplikaci používáte, je to jednoduché řešení.

Hluboké kopie

Jedna důležitá věc, kterou je třeba zdůraznit, je, že všechny výše popsané metody provádějí pouze mělké kopie vašich polí. Pokud tedy máte například pole objektů, skutečné pole bude zkopírováno, ale základní objekty budou předány odkazem na nové pole.

Abychom demonstrovali tento problém, podívejme se na příklad:

let oldArr = [{foo: 'bar'}, {baz: 'qux'}];
let newArr = [...oldArr];
console.log(newArr === oldArr);
console.log(newArr[0] === oldArr[0]);
false
true

Zde můžete vidět, že zatímco skutečné pole je nové, objekty v něm nebyly. U některých aplikací to může být velký problém. Pokud se vás to týká, zde je několik dalších metod, které můžete vyzkoušet.

Lodash Clone Deep

Lodashovo _.cloneDeep metoda dělá přesně to samé jako _.clone() , kromě toho, že rekurzivně klonuje vše v poli (nebo objektu), které mu předáte. Pokud použijeme stejný příklad jako výše, můžeme to vidět pomocí _.cloneDeep() nám poskytne nové pole a zkopírované prvky pole:

const _ = require('lodash');

let oldArr = [{foo: 'bar'}, {baz: 'qux'}];
let newArr = _.cloneDeep(oldArr);
console.log(newArr === oldArr);
console.log(newArr[0] === oldArr[0]);
false
false

Metody JSON

JavaScript poskytuje některé užitečné metody JSON, které zpracovávají převod většiny datových typů JS na řetězec a poté platný řetězec JSON na objekt JS. Příslušné metody se používají následovně:

let oldArr = [{foo: 'bar'}, {baz: 'qux'}];
let arrStr = JSON.stringify(oldArr);
console.log(arrStr);

let newArr = JSON.parse(arrStr);
console.log(newArr);

console.log(newArr === oldArr);
console.log(newArr[0] === oldArr[0]);

Zdarma e-kniha:Git Essentials

Prohlédněte si našeho praktického průvodce učením Git s osvědčenými postupy, průmyslově uznávanými standardy a přiloženým cheat sheetem. Přestaňte používat příkazy Google Git a skutečně se naučte to!

'[{"foo":"bar"},{"baz":"qux"}]'
[ { foo: 'bar' }, { baz: 'qux' } ]
false
false

Tato metoda funguje skvěle a nevyžaduje žádné knihovny třetích stran. Existují však dva hlavní problémy:

  • Data musí být serializovatelná a deserializovatelná prostřednictvím JSON
  • Použití metod JSON tímto způsobem je mnohem pomalejší než jiná řešení

Pokud tedy máte data, která nelze serializovat do JSON, nebo pokud je pro vaši aplikaci důležitá rychlost, pak to pro vás nemusí být dobré řešení.

Závěr

V tomto článku jsem popsal řadu způsobů, jak můžete kopírovat pole v JavaScriptu, a to jak pomocí nativního kódu, tak i užitečné knihovny třetích stran v Lodash. Také jsme se podívali na problém polí hlubokého klonování a na to, jaká řešení existují k jeho vyřešení.

Existuje jiná metoda, která vám nejlépe vyhovuje? Dejte nám vědět, co si myslíte v komentářích.