Sådan fungerer array.prototype.map ()

JavaScript er et allestedsnærværende sprog nu. Når den er begrænset til klientsides brug, kan du nu finde den på servere i mange varianter. Da JavaScript voksede, voksede også dets arsenal af funktioner, som brugerne kan bruge. De fleste gange er du tilfredse med disse metoder, og kun sjældent vil du tage det ekstra skridt for at forstå, hvad der virkelig foregår under emhætten.

På dette notat, lad os tage det ekstra skridt i dag og udforske en meget populær funktion: Array.prototype.map().

Ansvarsfraskrivelse : Jeg forklarer ikke, hvordan man bruger map()- eksemplet nedenfor illustrerer det, eller du kan finde adskillige eksempler, når du googler. Lad os i stedet dvæle ved, hvordan kort faktisk bliver implementeret bag kulisserne.

Den map()metode skaber en ny array med resultatet af at kalde en forudsat funktion på hvert enkelt element i den kaldende array.

Eksempel:

var array1 = [1, 4, 9, 16]; // pass a function to map const map1 = array1.map(x => x * 2); console.log(map1); // expected output: Array [2, 8, 18, 32]

Implementering

Lad os vælge implementeringen lige fra hestens mund og prøve at dissekere den. Nedenfor er MDN polyfill. Brug lidt tid på at forstå koden, og kopier den, og kør den på din maskine. Hvis du er en nybegynder / mellemliggende JavaScript-udvikler, vil du helt sikkert løbe ind i mindst et par spørgsmål.

/*Array.prototype.map implementation*/ Array.prototype.map = function (callback/*, thisArg*/) { var T, A, k; if (this == null) { throw new TypeError('this is null or not defined'); } var O = Object(this); var len = O.length >>> 0; if (typeof callback !== 'function') { throw new TypeError(callback + ' is not a function'); } if (arguments.length > 1) { T = arguments[1]; } A = new Array(len); k = 0; while (k < len) { var kValue, mappedValue; if (k in O) { kValue = O[k]; mappedValue = callback.call(T, kValue, k, O); A[k] = mappedValue; } k++; } return A; };

Jeg har fremhævet nogle få almindelige spørgsmål, der kan opstå i nedenstående kodekommentarer.

/*Array.prototype.map implementation*/ Array.prototype.map = function (callback/*, thisArg*/) { var T, A, k; if (this == null) { throw new TypeError('this is null or not defined'); } var O = Object(this); var len = O.length >>> 0;// QUESTION 1 : What is the need for this line of code? if (typeof callback !== 'function') { throw new TypeError(callback + ' is not a function'); } if (arguments.length > 1) { T = arguments[1]; } // QUESTION 2 :What is the need for the if condition and why are we assiging T=arguments[1]? A = new Array(len); k = 0; while (k < len) { var kValue, mappedValue; if (k in O) { kValue = O[k]; mappedValue = callback.call(T, kValue, k, O); // QUESTION 3: why do we pass T,k and O when all you need is kvalue? A[k] = mappedValue; } k++; } return A; };

Lad os adressere hver af dem startende fra bunden

SPØRGSMÅL 3: Hvorfor passerer vi T, k og O, når alt hvad du behøver er kVærdi?

mappedValue = callback.call(T, kValue, k, O);

Dette er den enkleste af de tre spørgsmål, så jeg har valgt dette til at begynde med. I de fleste tilfælde ville det være tilstrækkeligt at overføre kValue til tilbagekaldet, men:

  • Hvad hvis du har en brugssag, hvor du kun har brug for at udføre en operation på alle andre elementer? Nå, du har brug for et indeks, som er (k) .
  • Tilsvarende kan der være andre brugstilfælde, hvor du har brug for selve arrayet (O) for at være tilgængeligt i tilbagekaldet.
  • Hvorfor T ? For nu ved du bare, at T bliver sendt rundt for at opretholde sammenhæng. Du vil forstå dette bedre, når du er færdig med spørgsmål 2.

SPØRGSMÅL 2: Hvad er behovet for if-betingelsen, og hvorfor tildeler vi T = argumenter [1]?

if (arguments.length > 1) { T = arguments[1]; }

Kortfunktionen i ovenstående implementering har to argumenter: tilbagekald og den valgfri thisArg . Callback er et obligatorisk argument, mens denneArg er valgfri.

Man kan videregive, hvad der skal være "denne" -værdien inde i tilbagekaldet ved at give det andet valgfrie argument. Dette er grunden til, at koden kontrollerer, om der er mere end et argument og tildeler det andet valgfri argument til en variabel, der kan videregives til tilbagekaldet.

For at illustrere bedre, lad os sige, at du har et mock-krav, hvor du har brug for at returnere nummeret / 2, hvis det er deleligt med 2, og hvis det ikke er deleligt med 2, skal du returnere brugernavnet på den kaldende person. Nedenstående kode illustrerer, hvordan du kan få dette til at ske:

const myObj = { user: "John Smith" } var x = [10, 7]; let output = x.map(function (n) { if (n % 2 == 0) { return n / 2; } else { return this.user } }, myObj) // myObj is the second optional argument arguments[1] console.log(output); // [5,'John Smith'] //if you run the program without supplying myObj it would be //undefined as it cannot access myObj values console.log(output); // [ 5, undefined ]

SPØRGSMÅL 1: Hvad er behovet for denne kodelinje?

var len = O.length >>> 0

Denne tog noget tid for mig at finde ud af. Der foregår meget i denne kodelinje. I JavaScript har du evnen til at omdefinere "dette" inden for en funktion ved at påkalde metoden ved hjælp af opkald . Du kan også gøre dette ved hjælp af bind eller anvend , men til denne diskussion kan vi holde fast i opkaldet.

const anotherObject={length:{}} const myObj = { user: "John Smith" } var x = [10, 7]; let output = x.map.call(anotherObject,function (n) { if (n % 2 == 0) {return n / 2;} else {return this.user} }, myObj)

Når du påberåber dig ved hjælp af opkald,den første parameter ville være den kontekst, hvor kortfunktionen udføres. Ved at sende parameteren overskriver du "dette" inde på kortet med "dette" fra et andet objekt.

Hvis du observerer, er egenskaben længde for et andet objekt et tomt objekt og ikke et heltal. Hvis du bare bruger O.length i stedet for O.length> >> 0, ville det resultere i en udefineret værdi. Ved nulskift konverterer du faktisk eventuelle brøker og ikke-heltal til et heltal. I dette tilfælde vil resultatet blive tvunget til 0.

De fleste brugssager har ikke brug for denne kontrol, men der kan være en kanttilstand, hvor denne slags scenarier skal håndteres. De gode programmører, der designede specifikationen, tænkte det virkelig igennem! Når vi taler om specifikationen, kan du faktisk finde specifikationen for, hvordan hver funktion skal implementeres i Ecmascript her:

ECMAScript Language Specification - ECMA-262 Edition 5.1

Dette dokument og mulige oversættelser af det kan kopieres og leveres til andre og afledte værker, der kommenterer ...

www.ecma-international.org

Specifikationen ( trin 3 ) siger tydeligt, at længden skal være et 32 ​​bit usigneret heltal. Dette er grunden til, at vi nul udfylder forskydning for at sikre, at længden er et heltal, da kort i sig selv ikke kræver, at denne værdi er et array-objekt.

Det er det!

Jeg vil gerne takke par mennesker, jeg har aldrig mødt dem, men de var venlige nok til at tage tid (i internetfora) og hjælpe mig med at forstå få nuancer.

Salathiel Genese, Jordan Harband - tak!

Bemærk: Hvis du sidder fast på en anden linje kode, er du velkommen til at sætte det i kommentarerne, og jeg vil gøre mit bedste for at afklare.

Tak for din tid og glade kodning!