Jedyną różnicą, jaką widzę w map i foreach, jest to, że map
zwraca tablicę, a forEach
nie jest. Jednak nie rozumiem nawet ostatniego wiersza forEach
metody „ func.call(scope, this[i], i, this);
”. Na przykład, nie jest „ this
” i „ scope
”, odnosząc się do tego samego obiektu, a nie jest this[i]
, a i
odnosząc się do aktualnej wartości w pętli?
Zauważyłem w innym poście, że ktoś powiedział: „Użyj, forEach
gdy chcesz coś zrobić na podstawie każdego elementu listy. Możesz na przykład dodawać rzeczy do strony. Zasadniczo jest świetny, gdy chcesz mieć„ efekty uboczne ”. Nie wiem, co oznaczają skutki uboczne.
Array.prototype.map = function(fnc) {
var a = new Array(this.length);
for (var i = 0; i < this.length; i++) {
a[i] = fnc(this[i]);
}
return a;
}
Array.prototype.forEach = function(func, scope) {
scope = scope || this;
for (var i = 0, l = this.length; i < l; i++) {
func.call(scope, this[i], i, this);
}
}
Wreszcie, czy istnieją jakieś rzeczywiste zastosowania tych metod w javascript (ponieważ nie aktualizujemy bazy danych) inne niż manipulowanie liczbami w następujący sposób:
alert([1,2,3,4].map(function(x){ return x + 1})); //this is the only example I ever see of map in javascript.
Dzięki za każdą odpowiedź.
źródło
map
iforEach
? Wszystko, co otrzymuję od Google, to specyfikacje użytkowania i samouczki.Odpowiedzi:
Zasadnicza różnica między
map
iwforEach
twoim przykładzie polega na tym, żeforEach
operuje na oryginalnych elementach tablicy, podczas gdymap
jawnie zwraca jako wynik nową tablicę.Z tym,
forEach
że wykonujesz jakąś akcję z - i opcjonalnie zmieniasz - każdy element w oryginalnej tablicy.forEach
Metoda uruchamia funkcję dostarczania dla każdego elementu, ale nic nie zwraca (undefined
). Z drugiej stronymap
przechodzi przez tablicę, stosuje funkcję do każdego elementu i emituje wynik jako nową tablicę .„Efekt uboczny”
forEach
polega na tym, że oryginalna tablica jest zmieniana. „Brak efektu ubocznego”map
oznacza, że w użyciu idiomatycznym oryginalne elementy tablicy nie są zmieniane; nowa tablica to mapowanie jeden do jednego każdego elementu w oryginalnej tablicy - transformacja odwzorowania jest dostarczoną funkcją.Fakt, że nie ma żadnej bazy danych, nie oznacza, że nie będziesz musiał operować na strukturach danych, co jest przecież jedną z esencji programowania w jakimkolwiek języku. Jeśli chodzi o twoje ostatnie pytanie, twoja tablica może zawierać nie tylko liczby, ale także obiekty, ciągi znaków, funkcje itp.
źródło
.map
może zrobić wszystko, co.forEach
może (w tym modyfikować elementy), po prostu zwraca nową listę utworzoną z funkcji iteratora..map()
tworzy nową tablicę i nie zmienia oryginału. Rzeczywiście można zmodyfikować tablicę, która sama jest mapowana, ale byłoby to co najmniej nie idiomatyczne, jeśli nie bezsensowne..forEach()
, chociaż podobnie, stosuje swoją funkcję do każdego elementu, ale zawsze zwracaundefined
. Niezależnie od powyższego, OP pyta również o własne specyficzne funkcje dodane do prototypu tablicy; w przeszłości nie było tu ES5.forEach
ma nic takiego , czego nie możesz zrobićmap
. Możesz po prostu nie przejmować się wartością zwracaną zmap
i miałbyś rozszerzenieforEach
. Różnica polega na tym, że jest bardzo nieefektywne wmap
przypadku zadań, w których nie chcesz tworzyć nowej tablicy na podstawie wyników. Więc dla nich używaszforEach
.for
pętli. Nie zaprzeczam, że jest jakaś różnica w „skuteczności”, ale też nie sądzę, żeby ktokolwiek twierdził, że jeden ma jakąś magię, której druga nie może jakoś osiągnąć. Chociaż w rzeczywistości jest jedna rzecz,map
której nie można zrobić: nie zwracać tablicy. Jest to wartość posiadaniem JS sprostać oczekiwaniom innych językach, z zachowaniem funkcjonalnych ulubionych jakmap
,reduce
,filter
, itd. Na przykład, można realizowaćreduceRight
przy użyciu podobnych bloków, ale dlaczego nie wystarczy użyćreduceRight
?b.val = b.val**2
wewnątrz zwróconego obiektu . Dokładnie taka rzecz, o której mówimy, jest rzeczywiście możliwa, ale myląca i nie idiomatyczna. Zwykle po prostu zwracasz nową wartość, nie przypisując jej również do oryginalnej tablicy:a=[{val:1},{val:2},{val:3},{val:4}]; a.map((b)=>{b.val**2}); JSON.stringify(a);
Główną różnicą między tymi dwoma metodami jest koncepcyjny i stylistyczną: użyć
forEach
, gdy chcesz zrobić coś do lub z każdego elementu tablicy (robi „z” jest to, co po zacytowanie rozumie się przez „skutków ubocznych”, jak sądzę) , podczasmap
gdy używasz, gdy chcesz skopiować i przekształcić każdy element tablicy (bez zmiany oryginału).Ponieważ oba
map
iforEach
wywołują funkcję na każdym elemencie tablicy, a ta funkcja jest zdefiniowana przez użytkownika, prawie nic nie można zrobić z jednym, a nie z drugim. Możliwe jest, choć brzydkie, użyciemap
do modyfikacji tablicy w miejscu i / lub zrobienia czegoś z elementami tablicy:var a = [{ val: 1 }, { val: 2 }, { val: 3 }]; a.map(function(el) { el.val++; // modify element in-place alert(el.val); // do something with each element }); // a now contains [{ val: 2 }, { val: 3 }, { val: 4 }]
ale dużo czystsze i bardziej oczywiste, jeśli chodzi o zamiar użycia
forEach
:var a = [{ val: 1 }, { val: 2 }, { val: 3 }]; a.forEach(function(el) { el.val++; alert(el.val); });
Zwłaszcza jeśli, jak to zwykle bywa w prawdziwym świecie,
el
jest to użyteczna zmienna czytelna dla człowieka:cats.forEach(function(cat) { cat.meow(); // nicer than cats[x].meow() });
W ten sam sposób możesz łatwo użyć
forEach
do utworzenia nowej tablicy:var a = [1,2,3], b = []; a.forEach(function(el) { b.push(el+1); }); // b is now [2,3,4], a is unchanged
ale jest czystszy w użyciu
map
:var a = [1,2,3], b = a.map(function(el) { return el+1; });
Zauważ również, że ponieważ
map
tworzy nową tablicę, prawdopodobnie powoduje to co najmniej pewne uderzenie w wydajność / pamięć, gdy wszystko, czego potrzebujesz, to iteracja, szczególnie w przypadku dużych tablic - patrz http://jsperf.com/map-foreachJeśli chodzi o powody, dla których chcesz używać tych funkcji, są one pomocne za każdym razem, gdy musisz wykonać manipulację tablicami w javascript, co (nawet jeśli mówimy tylko o javascript w środowisku przeglądarki) jest dość często, prawie zawsze uzyskujesz dostęp do tablicy, której nie zapisujesz ręcznie w swoim kodzie. Możesz mieć do czynienia z tablicą elementów DOM na stronie, danymi pobranymi z żądania AJAX lub danymi wprowadzonymi w formularzu przez użytkownika. Jednym z typowych przykładów, z którymi się spotykam, jest pobieranie danych z zewnętrznego interfejsu API, w którym możesz chcieć
map
przekształcić dane w żądany format, a następnie użyćforEach
do iteracji nowej tablicy w celu wyświetlenia jej użytkownikowi.źródło
.map()
cały czas używają do modyfikowania elementów wbudowanych. Miałem wrażenie, że to główna zaleta używania.map
over.forEach
.map
może modyfikować elementy, tak, ale stworzyłoby tablicę, której nie potrzebujesz. Powinieneś także rozważyć, w jaki sposób wybranie jednego lub drugiego pozwala czytelnikowi odgadnąć, czy masz skutki uboczne, czy nieGłosowana odpowiedź (od Kena Redlera) jest myląca.
Efekt uboczny w środkach informatyki że właściwością funkcja / metoda zmienia stan globalnej [wiki] . W pewnym wąskim sensie może to również obejmować czytanie ze stanu globalnego, a nie z argumentów. W programowaniu imperatywnym lub OO efekty uboczne pojawiają się przez większość czasu. I prawdopodobnie używasz tego, nie zdając sobie z tego sprawy.
Istotna różnica między
forEach
imap
polega na tym, żemap
alokuje pamięć i przechowuje zwracaną wartość, a jednocześnieforEach
ją odrzuca. Więcej informacji można znaleźć w specyfikacji emca .Jeśli chodzi o powód, dla którego ludzie mówią, że
forEach
jest używany, gdy chcesz mieć efekt uboczny, wartość zwracanaforEach
jest zawszeundefined
. Jeśli nie ma efektu ubocznego (nie zmienia stanu globalnego), to po prostu marnuje czas procesora. Optymalizujący kompilator wyeliminuje ten blok kodu i zastąpi go ostateczną wartością (undefined
).Nawiasem mówiąc, należy zauważyć, że JavaScript nie ma ograniczeń co do skutków ubocznych. Wciąż możesz modyfikować oryginalną tablicę wewnątrz
map
.var a = [1,2,3]; //original var b = a.map( function(x,i){a[i] = 2*x; return x+1} ); console.log("modified=%j\nnew array=%j",a,b); // output: // modified=[2,4,6] // new array=[2,3,4]
źródło
To piękne pytanie z nieoczekiwaną odpowiedzią.
Poniższe informacje oparte są na oficjalnym opisie
Array.prototype.map()
.Nie ma nic, co
forEach()
mogłoby to zrobićmap()
. Oznacza to, żemap()
jest ścisły super zestaw zforEach()
.Chociaż
map()
jest zwykle używany do tworzenia nowej tablicy, może być również używany do zmiany bieżącej tablicy. Poniższy przykład ilustruje to:var a = [0, 1, 2, 3, 4], mapped = null; mapped = a.map(function (x) { a[x] = x*x*x; return x*x; }); console.log(mapped); // logs [0, 1, 4, 9, 16] As expected, these are squares. console.log(a); // logs [0, 1, 8, 27, 64] These are cubes of the original array!!
W powyższym przykładzie
a
został dogodnie ustawiony taki, żea[i] === i
dlai < a.length
. Mimo to demonstruje mocmap()
, aw szczególności zdolność do zmiany tablicy, w której jest wywoływana.Uwaga 1:
Oficjalny opis sugeruje, że
map()
może nawet zmienić długość tablicy, na której jest wywołany! Jednak nie widzę (dobrego) powodu, aby to zrobić.Uwaga 2:
Chociaż
map()
mapa jest super zestawemforEach()
,forEach()
powinno być nadal używane, gdy ktoś chce zmienić daną tablicę. To wyjaśnia twoje intencje.Mam nadzieję, że to pomogło.
źródło
mapped = a.map(function (x, i, arr) { arr[i] = x * x * x; return x * x; });.
a.forEach(function(x, i, arr) { ...
, co jest koncepcyjnie bardziej poprawnym sposobem, gdy istnieje zamiar zmutowania każdego oryginalnego elementu w przeciwieństwie do mapowania wartości z jednej tablicy do drugiejMożesz używać
map
tak, jakby to byłoforEach
.Zrobi jednak więcej, niż musi.
scope
może być dowolnym przedmiotem; to wcale nie jest koniecznethis
.Jeśli chodzi o to, czy istnieją rzeczywiste zastosowania
map
iforEach
, a także zapytać, czy istnieją rzeczywiste zastosowania pętlifor
lubwhile
pętli.źródło
scope = scope || this
oznacza "jeśliscope
jest fałszywy (niezdefiniowany, null, fałsz itp.)this
zamiast tego ustaw zakres na i kontynuuj ".Chociaż wszystkie poprzednie pytania są poprawne, zdecydowanie dokonałbym innego rozróżnienia. Użycie
map
iforEach
może sugerować zamiar.Lubię używać,
map
gdy po prostu przekształcam istniejące dane w jakiś sposób (ale chcę się upewnić, że oryginalne dane są niezmienione.Lubię używać,
forEach
gdy modyfikuję kolekcję w miejscu.Na przykład,
var b = [{ val: 1 }, { val: 2 }, { val: 3 }]; var c = b.map(function(el) { return { val: el.val + 1 }; // modify element in-place }); console.log(b); // [{ val: 1 }, { val: 2 }, { val: 3 }] console.log(c); // [{ val: 3 }, { val: 4 }, { val: 5 }]
Moja praktyczna zasada to upewnienie się,
map
że zawsze tworzysz nowy obiekt / wartość do zwrócenia dla każdego elementu listy źródłowej i zwracasz go, zamiast wykonywać jakąś operację na każdym elemencie.Jeśli nie masz prawdziwej potrzeby modyfikowania istniejącej listy, modyfikowanie jej w miejscu nie ma sensu i lepiej pasuje do funkcjonalnych / niezmiennych stylów programowania.
źródło
Odpowiedź TL; DR -
map zawsze zwraca inną tablicę.
forEach tego nie robi. To do Ciebie należy decyzja, co zrobi. Jeśli chcesz, zwróć tablicę lub zrób coś innego, jeśli tego nie zrobisz.
W pewnych sytuacjach pożądana jest elastyczność. Jeśli to nie jest z tym, z czym masz do czynienia, użyj mapy.
źródło
Po raz kolejny czuję się jak nekromanta, dodając odpowiedź na pytanie, które padło 5 lat temu (szczęśliwie jest raczej niedawna aktywność, więc nie tylko ja przeszkadzam zmarłym :).
Inni już napisali o Twoim głównym pytaniu dotyczącym różnicy między funkcjami. Ale dla...
... to zabawne, że powinieneś zapytać. Właśnie dzisiaj napisałem fragment kodu, który przypisuje wiele wartości z wyrażenia regularnego do wielu zmiennych za pomocą map do transformacji. Został użyty do konwersji bardzo skomplikowanej struktury opartej na tekście na dane, które można wizualizować ... ale dla uproszczenia podam przykład z użyciem ciągów dat, ponieważ są one prawdopodobnie bardziej znane każdemu (choćby mój problem dotyczył dat zamiast mapy użyłbym obiektu Date, który sam by sobie świetnie poradził).
const DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})\.(\d{3})Z$/; const TEST_STRING = '2016-01-04T03:20:00.000Z'; var [ iYear, iMonth, iDay, iHour, iMinute, iSecond, iMillisecond ] = DATE_REGEXP // We take our regular expression and... .exec(TEST_STRING) // ...execute it against our string (resulting in an array of matches)... .slice(1) // ...drop the 0th element from those (which is the "full string match")... .map(value => parseInt(value, 10)); // ...and map the rest of the values to integers... // ...which we now have as individual variables at our perusal console.debug('RESULT =>', iYear, iMonth, iDay, iHour, iMinute, iSecond, iMillisecond);
Więc ... chociaż to był tylko przykład - i wykonałem tylko bardzo podstawową transformację danych (tylko dla przykładu) ... zrobienie tego bez mapy byłoby znacznie bardziej żmudnym zadaniem.
To prawda, jest napisane w wersji JavaScript, którą, jak sądzę, nie obsługuje jeszcze zbyt wiele przeglądarek (przynajmniej w pełni), ale - osiągamy to. Gdybym musiał uruchomić to w przeglądarce, uważam, że ładnie by się transponował.
źródło