Hakovi za stvaranje JavaScript nizova

Uvidni savjeti za stvaranje i kloniranje nizova u JavaScript-u.

Vrlo važan aspekt svakog programskog jezika su vrste podataka i strukture dostupne u jeziku. Većina programskih jezika pruža vrste podataka za predstavljanje i rad sa složenim podacima. Ako ste radili s jezika kao što su Python ili Ruby, trebali ste vidjeti vrste podataka kao što su popisi , garniture , torke , hashes , dicts , i tako dalje.

U JavaScript-u nema toliko složenih vrsta podataka - jednostavno imate nizove i objekte . Međutim, u ES6 jeziku je dodano nekoliko vrsta podataka i struktura, poput simbola , skupova i karata .

Nizovi u JavaScript-u su objekti nalik popisu s visokim svojstvom dužine i svojstvima cijelih brojeva kao indeksima.

U ovom članku dijelim nekoliko hakova za stvaranje novih JavaScript nizova ili kloniranje već postojećih.

Stvaranje nizova: konstruktor niza

Najpopularnija metoda za stvaranje nizova je upotreba doslovne sintakse niza , što je vrlo jednostavno. Međutim, kada želite dinamički kreirati nizove, sintaksa doslovnog niza ne mora uvijek biti najbolja metoda. Alternativna metoda je upotreba Arraykonstruktora.

Evo jednostavnog isječka koda koji prikazuje upotrebu Arraykonstruktora.

Iz prethodnog isječka možemo vidjeti da Arraykonstruktor kreira nizove različito, ovisno o argumentima koje prima.

Novi nizovi: definirane duljine

Pogledajmo pobliže što se događa prilikom stvaranja nove Arrayzadane duljine. Konstruktor samo postavlja lengthsvojstvo niza na zadanu duljinu, bez postavljanja tipki.

Iz gornjeg isječka možda ćete doći u napast pomisliti da je svaki ključ u polju postavljen na vrijednost undefined. Ali stvarnost je takva da te tipke nikada nisu postavljene (ne postoje).

Sljedeća ilustracija to čini jasnijim:

To ga čini beskorisno pokušavati koristiti bilo koju od metoda niz ponavljanja, kao što su map(), filter()ili reduce()manipulirati niz. Recimo da svaki indeks u polju želimo ispuniti brojem 5kao vrijednošću. Pokušat ćemo sljedeće:

Vidimo da ovdje map()to nije uspjelo, jer svojstva indeksa ne postoje u polju - lengthpostoji samo svojstvo.

Pogledajmo različite načine na koje možemo riješiti ovaj problem.

1. Korištenje Array.prototype.fill ()

fill()Način ispunjava sve elemente niza iz indeksa početka do krajnjeg indeks s fiksnom vrijednošću. Krajnji indeks nije uključen. Ovdje možete saznati više fill().

Imajte na umu da fill()će raditi samo u preglednicima s podrškom za ES6.

Evo jednostavne ilustracije:

Ovdje smo uspjeli ispuniti sve elemente našeg stvorenog niza 5. Pomoću fill()metode možete postaviti bilo koju statičku vrijednost za različite indekse polja .

2. Korištenje Array.from ()

Array.from()Način stvara novi, plitku-kopirati Arrayprimjer iz niza nalik ili iterable objekta. Ovdje možete saznati više Array.from().

Imajte na umu da Array.from()će raditi samo u preglednicima s podrškom za ES6.

Evo jednostavne ilustracije:

Ovdje sada imamo undefinedpostavljene prave vrijednosti za svaki element polja koji se koristi Array.from(). To znači da sada možemo koristiti metode poput .map()i .filter()na polju, budući da svojstva indeksa sada postoje.

Još jedna stvar vrijedna pažnje Array.from()je da može uzeti i drugi argument, a to je funkcija karte. Pozvat će se za svaki element niza. Zbog toga je suvišno pozivanje .map()nakon Array.from().

Evo jednostavnog primjera:

3. Korištenje operatora širenja

Operator širenja( ...), dodan u ES6, može se koristiti za širenje elemenata niza, postavljajući nedostajuće elemente na vrijednost od undefined. To će proizvesti isti rezultat kao i jednostavno pozivanje Array.from()samo niza kao jedinog argumenta.

Evo jednostavne ilustracije korištenja operatora širenja:

Možete nastaviti i koristiti metode poput .map()i .filter()na polju, jer svojstva indeksa sada postoje.

Korištenje Array.of ()

Baš kao što smo vidjeli kod stvaranja novih nizova pomoću Arraykonstruktora ili funkcije, Array.of()ponaša se na vrlo sličan način. Zapravo, jedina razlika između Array.of()i Arrayje u načinu na koji obrađuju jedan cjelobrojni argument koji im je proslijeđen.

Dok Array.of(5)stvara novi niz s jednim elementom, 5i svojstvo length 1, Array(5)stvara novi prazan niz s 5 praznih mjesta i svojstvom length 5.

var array1 = Array.of(5); // [5] var array2 = Array(5); // Array(5) {length: 5}

Osim ove velike razlike, Array.of()ponaša se baš kao i Arraykonstruktor. Ovdje možete saznati više Array.of().

Imajte na umu da Array.of()će raditi samo u preglednicima s podrškom za ES6.

Pretvaranje u nizove: nizovi koji se sviđaju i koji se mogu kombinirati

Ako dovoljno dugo pišete JavaScript funkcije, trebali biste već znati o argumentsobjektu - koji je objekt nalik na niz dostupan u svakoj funkciji da sadrži popis argumenata koje je funkcija primila. Iako argumentsobjekt izgleda poput niza, nema pristup Array.prototypemetodama.

Prije ES6, obično biste vidjeli isječak koda kao što je sljedeći kada pokušavate pretvoriti argumentsobjekt u niz:

Pomoću Array.from()ili operatora širenja možete prikladno pretvoriti bilo koji objekt sličan nizu u niz. Stoga, umjesto da ovo radimo:

var args = Array.prototype.slice.call(arguments);

možete učiniti bilo što od ovoga:

// Using Array.from() var args = Array.from(arguments); // Using the Spread operator var args = [...arguments];

To se također odnosi na iterable kako je prikazano na sljedećoj ilustraciji:

Studija slučaja: Funkcija dometa

Kao studiju slučaja prije nego što nastavimo, stvorit ćemo jednostavnu range()funkciju za implementaciju novog hakova niza koji smo upravo naučili. Funkcija ima sljedeći potpis:

range(start: number, end: number, step: number) => Array

Evo isječka koda:

U ovom isječku koda koristili Array.from()smo stvaranje novog niza raspona dinamičke duljine, a zatim ga popunjavali uzastopno uvećanim brojevima pružajući funkciju mapiranja.

Imajte na umu da gornji isječak koda neće raditi za preglednike bez podrške za ES6, osim ako koristite polifil.

Evo nekoliko rezultata pozivanja range()funkcije definirane u gornjem isječku koda:

Demo kôd uživo možete dobiti pokretanjem sljedeće olovke na Codepenu :

Nizovi kloniranja: izazov

U JavaScriptu su nizovi i objekti referentne vrste. To znači da kada je varijabli dodijeljen niz ili objekt, ono što se dodjeljuje varijabli je referenca na mjesto u memoriji gdje je niz ili objekt bio pohranjen.

Nizovi su, kao i svaki drugi objekt u JavaScript-u, referentne vrste. To znači da se nizovi kopiraju referencom, a ne vrijednošću.

Pohranjivanje referentnih vrsta na ovaj način ima sljedeće posljedice:

1. Slični nizovi nisu jednaki.

Ovdje vidimo da premda array1i array2sadrže naizgled iste specifikacije niza, one nisu jednake. To je zato što referenca na svaki niz ukazuje na različito mjesto u memoriji.

2. Nizovi se kopiraju referencom, a ne vrijednošću.

Ovdje pokušavamo kopirati array1na array2, ali ono što u osnovi radimo je usmjeravanje array2na isto mjesto u memoriji na koje array1pokazuje. Dakle, oba array1i array2ukazuju na isto mjesto u memoriji i jednaki su.

Implikacija ovoga je da kada napravimo promjenu array2uklanjanjem posljednje stavke, uklanja se i posljednja stavka array1. To je zato što je promjena zapravo izvršena na nizu pohranjenom u memoriji, dok su array1i array2samo pokazivači na to isto mjesto u memoriji gdje je niz pohranjen.

Nizovi kloniranja: Hakovi

1. Korištenje Array.prototype.slice ()

slice()Postupak stvara plitku kopiju dijela niz bez mijenjanja polje. Ovdje možete saznati više slice().

Trik je u tome da pozovete slice()sa 0kao jedini argument ili bez ikakvih argumenata:

// with O as only argument array.slice(0); // without argument array.slice();

Evo jednostavne ilustracije kloniranja niza sa slice():

Ovdje možete vidjeti da array2je to klon array1s istim predmetima i duljinom. Međutim, oni ukazuju na različita mjesta u memoriji i kao rezultat toga nisu jednaki. Također primjećujete da kada izvršimo promjenu array2uklanjanjem posljednje stavke, array1ostaje nepromijenjen.

2. Korištenje Array.prototype.concat ()

concat()Metoda se koristi za spajanje dva ili više polja, što je rezultiralo u novi niz, dok se izvorna polja ostaje nepromijenjena. Ovdje možete saznati više concat().

Trik je u pozivu concat()s praznim nizom ( []) kao argumentom ili bez ikakvih argumenata:

// with an empty array array.concat([]); // without argument array.concat();

Kloniranje niza s concat()prilično je slično korištenju slice(). Evo jednostavne ilustracije kloniranja niza sa concat():

3. Korištenje Array.from ()

Kao što smo vidjeli ranije, Array.from()može se koristiti za stvaranje novog niza koji je plitka kopija izvornog niza. Evo jednostavne ilustracije:

4. Korištenje destrukturiranja nizova

Uz ES6 u svom alatu imamo neke moćnije alate poput destrukturiranja , širenjaoperator , funkcije strelice i tako dalje. Destrukturiranje je vrlo moćan alat za izdvajanje podataka iz složenih vrsta poput nizova i objekata.

Trik je u korištenju tehnike koja se naziva parametri odmora, a koja uključuje kombinaciju destrukturiranja niza i operatora širenja kako je prikazano u sljedećem isječku:

let [...arrayClone] = originalArray;

Gornji isječak stvara varijablu s imenom arrayClonekoja je klon originalArray. Evo jednostavne ilustracije kloniranja niza pomoću destrukturiranja niza:

Kloniranje: plitko nasuprot dubokom

Sve tehnike kloniranja niza koje smo do sada istraživali daju plitku kopiju niza. To neće predstavljati problem ako niz sadrži samo primitivne vrijednosti. Međutim, ako niz sadrži ugniježđene reference objekta, te će reference ostati netaknute čak i kad je niz kloniran.

Evo vrlo jednostavne demonstracije ovoga:

Primijetite da je modificiranje ugniježđenog niza u array1također izmijenilo ugniježđeni niz u array2i obrnuto.

Rješenje ovog problema je stvaranje dubinske kopije niza, a postoji nekoliko načina za to.

1. JSON tehnika

Dubinski primjerak niza najlakši je način kombinacijom JSON.stringify()i JSON.parse().

JSON.stringify()pretvara JavaScript vrijednost u valjani JSON niz, dok JSON.parse()pretvara JSON niz u odgovarajuću JavaScript vrijednost ili objekt.

Evo jednostavnog primjera:

JSON tehnika ima nekih nedostataka, posebno kada su u pitanju vrijednosti koje nisu nizovi, brojevi i logičke vrijednosti.

Te se nedostatke u JSON tehnici uglavnom mogu pripisati načinu na koji JSON.stringify()metoda pretvara vrijednosti u JSON niz.

Evo jednostavne demonstracije ove pogreške u pokušaju JSON.stringify()vrijednosti koja sadrži ugniježđenu funkciju.

2. Pomoćnik za duboko kopiranje

Izvodljiva alternativa JSON tehnici bit će implementacija vlastite pomoćne funkcije dubokog kopiranja za kloniranje referentnih tipova bilo da su to nizovi ili objekti.

Evo vrlo jednostavne i minimalističke funkcije dubokog kopiranja koja se naziva deepClone:

Sada ovo nije najbolja od funkcija dubinskog kopiranja, kao što ćete uskoro vidjeti s nekim JavaScript knjižnicama - međutim, dubinsko kopiranje izvodi u prilično dobroj mjeri.

3. Korištenje JavaScript knjižnica

Pomoćna funkcija dubinske kopije koju smo upravo definirali nije dovoljno robusna u kloniranju svih vrsta JavaScript podataka koji mogu biti ugniježđeni unutar složenih objekata ili nizova.

JavaScript knjižnice poput Lodash i jQuery pružaju robusnije uslužne funkcije dubokog kopiranja s podrškom za različite vrste JavaScript podataka.

Evo primjera koji koristi _.cloneDeep()iz knjižnice Lodash:

Evo istog primjera, ali korištenja $.extend()iz biblioteke jQuery:

Zaključak

U ovom smo članku uspjeli istražiti nekoliko tehnika za dinamičko stvaranje novih nizova i kloniranje već postojećih, uključujući pretvaranje objekata sličnih nizu i iterabli u nizove.

Također smo vidjeli kako nam neke od novih značajki i poboljšanja uvedenih u ES6 mogu omogućiti učinkovito izvođenje određenih manipulacija na nizovima.

Koristili smo značajke poput destrukturiranja i operatora širenja za kloniranje i širenje nizova. Iz ovog članka možete saznati više o destrukturiranju.

Pljeskajte i slijedite

Ako vam je ovaj članak bio pronicljiv, možete slobodno aplauzom uputiti ako vam ne smeta.

Također me možete pratiti na Medium (Glad Chinda) za preglednije članke koji će vam možda biti od pomoći. Možete me pratiti i na Twitteru (@gladchinda).

Sretno hakiranje ...