Kako radi array.prototype.map ()

JavaScript je sada sveprisutan jezik. Nekad ograničeno na upotrebu na strani klijenta, sada ga možete pronaći na poslužiteljima u raznim okusima. Kako je JavaScript rastao, tako je rastao i njegov arsenal funkcija koje korisnici mogu koristiti. Većinom se zadovoljite ovim metodama i rijetko ćete poželjeti poduzeti taj dodatni korak da biste razumjeli što se zapravo događa ispod haube.

Na napomenu da, uzmimo taj dodatni korak i danas istražuju vrlo popularan funkciju: Array.prototype.map().

Izjava o odricanju odgovornosti : Neću objašnjavati kako se koristi map()- donji primjer to ilustrira ili možete pronaći brojne primjere kada guglate. Umjesto toga, zadržimo se na tome kako se karta zapravo implementira iza kulisa.

map()Način stvara novi niz sa rezultatom pozivanja pruža funkciju na svaki element u zvanje polja.

Primjer:

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]

Provedba

Odaberimo primjenu iz usta konja i pokušajmo je secirati. Ispod je MDN polifil. Provedite neko vrijeme razumijevajući kôd, kopirajte ga i pokrenite na vašem stroju. Ako ste početnik / srednji programer za JavaScript, zasigurno ćete naletjeti na barem nekoliko pitanja.

/*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; };

Istaknuo sam nekoliko uobičajenih pitanja koja se mogu pojaviti u komentarima koda u nastavku.

/*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; };

Obratimo se svakom od njih počevši od dna

PITANJE 3: Zašto prolazimo T, k i O kad vam treba samo kValue?

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

Ovo je najjednostavnije od tri pitanja, pa sam za početak izabrao ovo. U većini slučajeva prolazi kValue za povratni poziv će biti dovoljno, ali:

  • Što ako imate slučaj upotrebe u kojem trebate izvršiti operaciju samo nad svim ostalim elementima? Pa, potreban vam je indeks koji je (k) .
  • Slično tome, mogu postojati i drugi slučajevi upotrebe u kojima trebate da sam niz (O) bude dostupan u povratnom pozivu.
  • Zašto T ? Za sada samo znajte da se T prenosi kako bi se održao kontekst. To ćete bolje razumjeti kad završite s pitanjem 2.

PITANJE 2: Koja je potreba za uvjetom if i zašto dodjeljujemo T = argumente [1]?

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

Funkcija map u gornjoj implementaciji ima dva argumenta: povratni poziv i neobavezni thisArg . Povratni poziv je obvezni argument, dok je thisArg neobavezan.

Može se proslijediti ono što bi trebala biti vrijednost "ovo" unutar povratnog poziva davanjem drugog neobaveznog argumenta. Zbog toga kod provjerava postoji li više od jednog argumenta i drugi neobavezni argument dodjeljuje varijabli koja se može proslijediti povratnom pozivu.

Da bismo to bolje ilustrirali, recimo da imate lažni zahtjev gdje trebate vratiti broj / 2 ako je djeljiv sa 2, a ako nije djeljiv s 2, morate vratiti korisničko ime osobe koja zove. Kôd u nastavku ilustrira kako to možete postići:

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 ]

PITANJE 1: Što je potrebno za ovaj redak koda?

var len = O.length >>> 0

Ovo mi je trebalo neko vrijeme da shvatim. Mnogo se toga događa u ovom retku koda. U JavaScriptu imate mogućnost redefiniranja "ovog" unutar funkcije pozivanjem metode pomoću poziva . To možete učiniti i pomoću vezanja ili prijave , ali za ovu raspravu ostanite pri pozivu.

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)

Kada se pozivate pomoću poziva,prvi parametar bio bi kontekst u kojem se izvršava funkcija karte. Slanjem parametra prepisujete "ovo" unutar karte s "ovo" drugogObjekta.

Ako primijetite, svojstvo length drugogObject je prazan objekt, a ne cijeli broj. Ako samo koristite O.length umjesto O.length> >> 0, to bi rezultiralo nedefiniranom vrijednošću. Pomicanjem nule zapravo pretvarate sve razlomke i nebrojeve u cijeli broj. U ovom slučaju rezultat bi bio prisiljen na 0.

Većina slučajeva korištenja neće trebati ovu provjeru, ali možda postoji rubni slučaj u kojem treba riješiti ovu vrstu scenarija. Dobri programeri koji su dizajnirali specifikaciju zaista su dobro razmislili! Govoreći o specifikaciji, ovdje zapravo možete pronaći specifikaciju kako se svaka funkcija mora implementirati u Ecmascript:

Specifikacija jezika ECMAScript - ECMA-262 izdanje 5.1

Ovaj dokument i njegovi mogući prijevodi mogu se kopirati i dostaviti drugima, a izvedena djela koja komentiraju ...

www.ecma-international.org

Specifikacija ( korak 3 ) jasno kaže da duljina mora biti 32-bitni nepoznati cijeli broj. To je razlog zbog kojeg se pomicanje nula ispunjava kako bismo osigurali da je dužina cijeli broj, jer sama karta ne zahtijeva da ova vrijednost bude objekt Array.

To je to!

Želio bih zahvaliti par ljudi, nikad ih nisam upoznao, ali bili su ljubazni da odvoje vrijeme (na internetskim forumima) i pomognu mi da razumijem nekoliko nijansi.

Salathiel Genese, Jordan Harband - hvala!

Napomena: Ako ste zapeli na drugom retku koda, slobodno to dodajte u komentare i dat ću sve od sebe da to pojasnim.

Hvala na vašem vremenu i sretnom kodiranju!