Hacks til oprettelse af JavaScript Arrays

Insightful tip til oprettelse og kloning af matriser i JavaScript.

Originalfoto af Markus Spiske på Unsplash

Et meget vigtigt aspekt af ethvert programmeringssprog er de datatyper og strukturer, der er tilgængelige på sproget. De fleste programmeringssprog indeholder datatyper til at repræsentere og arbejde med komplekse data. Hvis du har arbejdet med sprog som Python eller Ruby, skulle du have set datatyper som lister, sæt, tuples, hashes, dicts osv.

I JavaScript er der ikke så mange komplekse datatyper - du har simpelthen matriser og objekter. I ES6 blev der dog tilføjet et par datatyper og strukturer til sproget, såsom symboler, sæt og kort.

Arrays i JavaScript er listelignende objekter på højt niveau med en længdeegenskab og heltalegenskaber som indekser.

I denne artikel deler jeg et par hacks til oprettelse af nye JavaScript-arrays eller kloning af allerede eksisterende.

Oprettelse af arrays: Array-konstruktøren

Den mest populære metode til oprettelse af matriser bruger array-bogstavelig syntaks, som er meget ligetil. Når du imidlertid dynamisk ønsker at oprette arrays, er den arktiske bogstavelige syntaks ikke altid den bedste metode. En alternativ metode er at bruge Array-konstruktøren.

Her er et simpelt kodestykker, der viser brugen af ​​Array-konstruktøren.

Fra det forrige uddrag kan vi se, at Array-konstruktøren opretter arrays forskelligt afhængigt af de argumenter, den modtager.

Nye arrays: med defineret længde

Lad os se nærmere på, hvad der sker, når vi opretter en ny matrix af en given længde. Konstruktøren indstiller bare arrayets længdeegenskab til den givne længde uden at indstille tasterne.

Fra ovenstående uddrag kan du blive fristet til at tro, at hver nøgle i matrixen var indstillet til en værdi af udefineret. Men virkeligheden er, at disse nøgler aldrig blev indstillet (de findes ikke).

Følgende illustration gør det tydeligere:

Dette gør det nytteløst at forsøge at bruge en hvilken som helst array-iterationsmetode, såsom kort (), filter () eller reducere () til at manipulere matrixen. Lad os sige, at vi ønsker at udfylde hvert indeks i matrixen med tallet 5 som en værdi. Vi forsøger følgende:

Vi kan se, at kortet () ikke virkede her, fordi indeksegenskaber ikke findes i matrixen - kun længdeegenskaben findes.

Lad os se forskellige måder, vi kan løse dette problem på.

1. Brug af Array.prototype.fill ()

Metoden fyld () udfylder alle elementerne i en matrix fra et startindeks til et slutindeks med en statisk værdi. Slutindekset er ikke inkluderet. Du kan lære mere om udfyldning () her.

Bemærk, at udfyldning () kun fungerer i browsere med ES6-support.

Her er en enkel illustration:

Her har vi været i stand til at udfylde alle elementerne i vores oprettede matrix med 5. Du kan indstille en hvilken som helst statisk værdi for forskellige indekser af arrayet ved hjælp af metoden fill ().

2. Brug af Array.from ()

Metoden Array.from () opretter en ny, lav-kopieret Array-forekomst fra et array-lignende eller iterable objekt. Du kan lære mere om Array.from () her.

Bemærk, at Array.from () kun fungerer i browsere med ES6-support.

Her er en enkel illustration:

Her har vi nu ægte udefinerede værdier, der er indstillet for hvert element i arrayet ved hjælp af Array.from (). Dette betyder, at vi nu kan gå videre og bruge metoder som .map () og .filter () på matrixen, da indeksegenskaber nu findes.

En ting, der er værd at bemærke ved Array.from (), er, at det kan tage et andet argument, som er en kortfunktion. Det kaldes på alle elementer i matrixen. Dette gør det overflødigt at kalde .map () efter Array.from ().

Her er et simpelt eksempel:

3. Brug af Spread Operator

Spredningsoperatøren (...), tilføjet i ES6, kan bruges til at sprede elementerne i matrixen og indstille de manglende elementer til en værdi af udefineret. Dette giver det samme resultat som blot at kalde Array.from () med kun arrayet som det eneste argument.

Her er en simpel illustration af brug af spredningsoperatøren:

Du kan gå videre og bruge metoder som .map () og .filter () på matrixen, da indeksegenskaber nu findes.

Brug af Array.of ()

Ligesom vi så med at oprette nye arrays ved hjælp af Array-konstruktøren eller -funktionen, opfører Array.of () sig på en meget lignende måde. Faktisk er den eneste forskel mellem Array.of () og Array i, hvordan de håndterer et enkelt heltalargument, der er sendt til dem.

Mens Array.of (5) opretter en ny matrix med et enkelt element, 5 og en længdeegenskab på 1, opretter Array (5) en ny tom array med 5 tomme slots og en længdeegenskab på 5.

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

Udover denne store forskel opfører Array.of () sig ligesom Array-konstruktøren. Du kan lære mere om Array.of () her.

Bemærk, at Array.of () kun fungerer i browsere med ES6-support.

Konvertering til Arrays: Array-likes og Iterables

Hvis du har skrevet JavaScript-funktioner længe nok, skal du allerede vide om argumenterobjektet - som er et array-lignende objekt, der er tilgængeligt i hver funktion til at indeholde listen over argumenter, den modtagne funktion. Selvom argumenterobjektet ligner meget en matrix, har den ikke adgang til metoderne Array.prototype.

Før ES6, ser du normalt et kodestykket som det følgende, når du prøver at konvertere argumenterobjektet til en matrix:

Med Array.from () eller spredningsoperatøren kan du nemt konvertere ethvert array-lignende objekt til en matrix. I stedet for at gøre dette:

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

du kan gøre en af ​​disse:

// Brug af Array.from ()
var args = Array.from (argumenter);
// Brug af Spread-operatoren
var args = [... argumenter];

Disse gælder også for iterables som vist på følgende illustration:

Casestudie: Range-funktion

Som et casestudie, før vi fortsætter, vil vi oprette en simpel rækkevidde () -funktion til at implementere det nye array-hack, vi netop har lært. Funktionen har følgende signatur:

rækkevidde (start: nummer, slut: nummer, trin: antal) => Array 

Her er kodestykket:

I dette kodestykket brugte vi Array.from () til at oprette den nye rækkevidde med dynamisk længde og derefter udfylde det sekventielt forøgede tal ved at tilvejebringe en kortlægningsfunktion.

Bemærk, at ovenstående kodestykket ikke fungerer for browsere uden ES6-understøttelse, medmindre du bruger polyfylder.

Her er nogle resultater fra opkald til funktionen rækkevidde (), der er defineret i ovenstående kodestykket:

Du kan få en demo med live kode ved at køre følgende pen på Codepen:

Cloning Arrays: The Challenge

I JavaScript er arrays og objekter referencetyper. Dette betyder, at når en variabel tildeles en matrix eller et objekt, hvad der får tildelt variablen, er en henvisning til det sted i hukommelsen, hvor arrayet eller objektet blev gemt.

Arrays, ligesom alle andre objekter i JavaScript, er referencetyper. Dette betyder, at matriser kopieres ved henvisning og ikke efter værdi.

Opbevaring af referencetyper på denne måde har følgende konsekvenser:

1. Lignende arrays er ikke ens.

Her ser vi, at selvom array1 og array2 indeholder tilsyneladende de samme array-specifikationer, er de ikke ens. Dette skyldes, at henvisningen til hver af matriserne peger på en anden placering i hukommelsen.

2. Arrays kopieres ved henvisning og ikke efter værdi.

Her forsøger vi at kopiere array1 til array2, men hvad vi dybest set gør er at pege array2 til den samme placering i hukommelsen, som array1 peger på. Derfor peger både array1 og array2 på den samme placering i hukommelsen og er ens.

Implikationen af ​​dette er, at når vi foretager en ændring af array2 ved at fjerne det sidste element, fjernes det sidste element i array1 også. Dette skyldes, at ændringen faktisk blev foretaget til den matrix, der er gemt i hukommelsen, mens array1 og array2 bare er pegepunkter til det samme sted i hukommelsen, hvor arrayet er gemt.

Kloning Arrays: The Hacks

1. Brug af Array.prototype.slice ()

Metoden skive () opretter en lav kopi af en del af en matrix uden at ændre array. Du kan lære mere om udsnit () her.

Tricket er at kalde skive () enten med0 som det eneste argument eller uden nogen argumenter overhovedet:

// med O som eneste argument
array.slice (0);
// uden argument
array.slice ();

Her er en simpel illustration af kloning af en matrix med skive ():

Her kan du se, at matrix2 er en klon af array1 med de samme emner og længde. De peger imidlertid på forskellige placeringer i hukommelsen, og er som et resultat ikke ens. Du bemærker også, at når vi foretager en ændring til array2 ved at fjerne det sidste emne, forbliver array1 uændret.

2. Brug af Array.prototype.concat ()

Metoden concat () bruges til at flette to eller flere arrays, hvilket resulterer i en ny matrix, mens de originale arrays forbliver uændrede. Du kan lære mere om concat () her.

Tricket er at kalde concat () enten med en tom matrix ([]) som argument eller uden nogen argumenter overhovedet:

// med et tomt array
array.concat ([]);
// uden argument
array.concat ();

Kloning af en matrix med concat () svarer ganske til at bruge skive (). Her er en simpel illustration af kloning af en matrix med concat ():

3. Brug af Array.from ()

Som vi så tidligere, kan Array.from () bruges til at oprette en ny matrix, som er en lav kopi af det originale array. Her er en enkel illustration:

4. Brug af Array Destructuring

Med ES6 har vi nogle mere kraftfulde værktøjer i vores værktøjskasse, såsom destruktion, spredt operatør, pilefunktioner og så videre. Destrukturering er et meget kraftfuldt værktøj til at udtrække data fra komplekse typer som arrays og objekter.

Du kan lære mere om destruktion fra denne artikel.

Tricket er at bruge en teknik kaldet hvileparametre, som involverer en kombination af array-destruktion og spredningsoperatøren som vist i følgende uddrag:

let [... arrayClone] = originalArray;

Ovenstående uddrag opretter en variabel, der hedder arrayClone, som er en klon af den originale Array. Her er en simpel illustration af kloning af en matrix ved hjælp af array-destruktion:

Kloning: Lavt kontra dyb

Alle array-kloningsteknikker, vi hidtil har undersøgt, producerer en lav kopi af matrixen. Dette vil ikke være et problem, hvis matrixen kun indeholder primitive værdier. Hvis arrayet dog indeholder indlejrede objektreferencer, forbliver disse referencer intakte, selv når arrayet er klonet.

Her er en meget enkel demonstration af dette:

Bemærk, at ændring af det indlejrede array i array1 også ændrede det indlejrede array i array2 og vice versa.

Løsningen på dette problem er at oprette en dyb kopi af matrixen, og der er et par måder at gøre dette på.

1. JSON-teknikken

Den nemmeste måde at oprette en dyb kopi af en matrix er ved at bruge en kombination af JSON.stringify () og JSON.parse ().

JSON.stringify () konverterer en JavaScript-værdi til en gyldig JSON-streng, mens JSON.parse () konverterer en JSON-streng til en tilsvarende JavaScript-værdi eller -objekt.

Her er et simpelt eksempel:

JSON-teknikken har nogle mangler, især når andre værdier end strenge, tal og boolæner er involveret.

Disse fejl i JSON-teknikken kan hovedsageligt tilskrives den måde, hvorpå JSON.stringify () -metoden konverterer værdier til JSON-streng.

Her er en simpel demonstration af denne fejl ved forsøg på at JSON.stringify () en værdi, der indeholder indlejret funktion.

2. Deep Copy Helper

Et levedygtigt alternativ til JSON-teknikken vil være at implementere din egen dybkopi-hjælperfunktion til kloning af referencetyper, hvad enten det drejer sig om arrays eller genstande.

Her er en meget enkel og minimalistisk dybkopifunktion kaldet deepClone:

Nu er dette ikke det bedste af dybe kopifunktioner derude, ligesom du snart ser med nogle JavaScript-biblioteker - det udfører dyb kopiering i temmelig godt omfang.

3. Brug af JavaScript-biblioteker

Den dybe kopihjælpefunktion, vi netop har defineret, er ikke robust nok til at klone alle slags JavaScript-data, der muligvis er indlejret i komplekse objekter eller arrays.

JavaScript-biblioteker som Lodash og jQuery giver mere robuste dybe kopifunktionsfunktioner med understøttelse af forskellige slags JavaScript-data.

Her er et eksempel, der bruger _.cloneDeep () fra Lodash-biblioteket:

Her er det samme eksempel, men ved hjælp af $ .extend () fra jQuery-biblioteket:

Konklusion

I denne artikel har vi været i stand til at udforske flere teknikker til dynamisk oprettelse af nye arrays og kloning af allerede eksisterende, herunder konvertering af matrixlignende objekter og iterables til arrays.

Vi har også set, hvordan nogle af de nye funktioner og forbedringer, der blev introduceret i ES6, kan gøre det muligt for os effektivt at udføre visse manipulationer på arrays.

Vi brugte funktioner som destruktion og spredningsoperatøren til kloning og spredning af arrays. Du kan lære mere om destruktion fra denne artikel.

Klap & følg

Hvis du fandt denne artikel indsigende, er du fri til at give nogle runder med bifald, hvis du ikke har noget imod det.

Du kan også følge mig på Medium (Glad Chinda) for mere indsigtsfulde artikler, som du måske kan hjælpe. Du kan også følge mig på Twitter (@gladchinda).

Glad hacking ...