Hacks til oprettelse af JavaScript-arrays

Indsigtige tip til oprettelse og kloning af arrays i JavaScript.

Et meget vigtigt aspekt af hvert programmeringssprog er de datatyper og strukturer, der er tilgængelige på sproget. De fleste programmeringssprog giver 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 , tupler , hashes , dikt osv.

I JavaScript er der ikke så mange komplekse datatyper - du har simpelthen arrays og objekter . Imidlertid blev der i ES6 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 Constructor

Den mest populære metode til oprettelse af arrays er at bruge arrayets syntaks, som er meget ligetil. Men når du vil oprette dynamisk arrays, er matrixens bogstavelige syntaks muligvis ikke altid den bedste metode. En alternativ metode er at bruge Arraykonstruktøren.

Her er et simpelt kodestykke, der viser brugen af Arraykonstruktøren.

Fra det forrige uddrag kan vi se, at Arraykonstruktø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 Arraymed en given længde. Konstruktøren indstiller netop lengthmatrixens egenskab 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 arrayet var indstillet til en værdi på undefined. 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 nogen af de vifte iteration metoder såsom map(), filter()eller reduce()at manipulere array. Lad os sige, at vi vil udfylde hvert indeks i arrayet med tallet 5som en værdi. Vi vil forsøge følgende:

Vi kan se, at map()det ikke fungerede her, fordi indeksegenskaberne ikke findes i arrayet - kun lengthejendommen findes.

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

1. Brug af Array.prototype.fill ()

Den fill()metode udfylder alle elementerne i et array fra en start indeks til en ende indeks med en statisk værdi. Slutindekset er ikke inkluderet. Du kan lære mere om fill()her.

Bemærk, at fill()det kun fungerer i browsere med ES6-understøttelse.

Her er en simpel illustration:

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

2. Brug af Array.from ()

Den Array.from()fremgangsmåde skaber en ny, lavvandet-kopieret Arrayeksempel fra et array-lignende eller Iterable objekt. Du kan lære mere om Array.from()her.

Bemærk, at Array.from()det kun fungerer i browsere med ES6-understøttelse.

Her er en simpel illustration:

Her har vi nu sat ægte undefinedværdier for hvert element i arrayet, der bruger Array.from(). Dette betyder, at vi nu kan gå videre og bruge metoder som .map()og .filter()på arrayet, da indeksegenskaberne nu findes.

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

Her er et simpelt eksempel:

3. Brug af Spread Operator

Den spredning operatør( ...), tilføjet i ES6, kan bruges til at sprede elementerne i arrayet og indstille de manglende elementer til en værdi på undefined. Dette vil give det samme resultat som bare at ringe Array.from()med kun arrayet som det eneste argument.

Her er en enkel illustration af brugen af ​​spredningsoperatøren:

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

Brug af Array.of ()

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

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

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

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

Bemærk, at Array.of()det kun fungerer i browsere med ES6-understøttelse.

Konvertering til arrays: Array-likes og Iterables

Hvis du har skrevet JavaScript-funktioner længe nok, skal du allerede vide om argumentsobjektet - som er et array-lignende objekt, der er tilgængeligt i hver funktion for at holde listen over argumenter, som funktionen modtog. Selvom argumentsobjektet ligner en matrix, har det ikke adgang til Array.prototypemetoderne.

Før ES6 vil du normalt se et kodestykke som følgende, når du prøver at konvertere argumentsobjektet til en matrix:

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

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

du kan gøre en af ​​disse:

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

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

Casestudie: Range-funktion

Som en casestudie, inden vi fortsætter, opretter vi en simpel range()funktion til at implementere det nye array-hack, vi lige har lært. Funktionen har følgende signatur:

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

Her er kodestykket:

I dette kodestykke brugte vi til Array.from()at oprette det nye intervalarray med dynamisk længde og derefter udfylde det sekventielt inkrementerede tal ved at give en kortlægningsfunktion.

Bemærk, at ovenstående kodestykke ikke fungerer for browsere uden ES6-understøttelse, undtagen hvis du bruger polyfills.

Her er nogle resultater fra at kalde range()funktionen defineret i ovenstående kodestykke:

Du kan få en live-kode-demo 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, er det, der tildeles variablen, 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 arrays kopieres ved reference og ikke efter værdi.

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

1. Lignende arrays er ikke ens.

Her ser vi, at selv om array1og array2indeholder tilsyneladende de samme array-specifikationer, er de ikke lige. Dette skyldes, at henvisningen til hver af arrays peger på en anden placering i hukommelsen.

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

Her forsøger vi at kopiere array1til array2, men hvad vi grundlæggende laver er at pege array2på den samme placering i hukommelsen, der array1peger på. Derfor både array1og array2peger på den samme placering i hukommelsen og er ens.

Implikationen af ​​dette er, at når vi foretager en ændring array2ved at fjerne det sidste element, bliver det sidste element array1også fjernet. Dette skyldes, at ændringen faktisk blev foretaget til array er lagret i hukommelsen, mens array1og array2er blot pegepinde til samme sted i hukommelsen, hvor array er gemt.

Cloning Arrays: The Hacks

1. Brug af Array.prototype.slice ()

Den slice()metode skaber en overfladisk kopi af en del af et array uden at ændre opstillingen. Du kan lære mere om slice()her.

Tricket er at kalde slice()enten med 0som det eneste argument eller uden nogen argumenter overhovedet:

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

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

Her kan du se, at der array2er en klon array1med samme genstande og længde. De peger dog på forskellige placeringer i hukommelsen og er derfor ikke ens. Du bemærker også, at når vi foretager en ændring array2ved at fjerne det sidste emne, array1forbliver uændret.

2. Brug af Array.prototype.concat ()

Den concat()metode, der anvendes til at sammenflette to eller flere arrays, hvilket resulterer i en ny matrix, mens den oprindelige arrays forbliver uændret. Du kan lære mere om concat()her.

Tricket er at kalde concat()enten med et tomt array ( []) som argument eller uden nogen som helst argumenter:

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

Kloning af en matrix concat()ligner meget at bruge slice(). Her er en simpel illustration af kloning af en matrix med concat():

3. Brug af Array.from ()

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

4. Brug af Array Destructuring

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

Tricket er at bruge en teknik kaldet hvileparametre, som involverer en kombination af array-destrukturering og spread-operatoren som vist i følgende uddrag:

let [...arrayClone] = originalArray;

Ovenstående uddrag opretter en variabel med navnet, arrayClonesom er en klon af originalArray. Her er en enkel illustration af kloning af en matrix ved hjælp af array-destrukturering:

Kloning: Lav kontra dyb

Alle de teknikker til array-kloning, vi hidtil har udforsket, producerer en lav kopi af arrayet. Dette vil ikke være et problem, hvis arrayet kun indeholder primitive værdier. Men hvis matrixen 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 array1også ændrede det indlejrede array i array2og omvendt.

Løsningen på dette problem er at oprette en dyb kopi af arrayet, 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 et array er ved hjælp af en kombination af JSON.stringify()og JSON.parse().

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

Her er et simpelt eksempel:

JSON-teknikken har nogle fejl, især når andre værdier end strenge, tal og booleanske 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 enkel demonstration af denne fejl ved at prøve at få 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 dybe kopihjælperfunktion til kloning af referencetyper, hvad enten det er arrays eller objekter.

Her er en meget enkel og minimalistisk dyb kopifunktion kaldet deepClone:

Nu er dette ikke det bedste af dybe kopifunktioner derude, som du snart vil se med nogle JavaScript-biblioteker - det udfører dog dyb kopiering i ret god grad.

3. Brug af JavaScript-biblioteker

Den dybe kopihjælperfunktion, vi lige har defineret, er ikke robust nok til at klone alle slags JavaScript-data, der kan være indlejret i komplekse objekter eller arrays.

JavaScript-biblioteker som Lodash og jQuery giver mere robuste funktioner til dybkopifunktion med understøttelse af forskellige typer JavaScript-data.

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

Her er det samme eksempel, men ved hjælp $.extend()af 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 array-lignende 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.

Klapp & følg

Hvis du fandt denne artikel indsigtsfuld, kan du give nogle 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 finder nyttige. Du kan også følge mig på Twitter (@gladchinda).

God hacking ...