Mam przedmiot:
myObject = { 'a': 1, 'b': 2, 'c': 3 }
Szukam metody natywnej, podobnej do Array.prototype.map
tej, która byłaby używana w następujący sposób:
newObject = myObject.map(function (value, label) {
return value * value;
});
// newObject is now { 'a': 1, 'b': 4, 'c': 9 }
Czy JavaScript ma taką map
funkcję dla obiektów? (Chcę tego dla Node.JS, więc nie dbam o problemy z przeglądarkami).
javascript
node.js
functional-programming
map-function
Randomblue
źródło
źródło
Object.keys
, które nie mają dobrze określonej kolejności. Może to być problematyczne, sugeruję użycieObject.getOwnPropertyNames
zamiast tego.Object.keys
iObject.getOwnPropertyNames
. Zobacz developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Object.keys
zależy od implementacji. Zobacz stackoverflow.com/a/30919039/1529630Odpowiedzi:
Nie ma rodzimy
map
się doObject
obiektu, ale jak o tym:Ale możesz łatwo iterować obiekt, używając
for ... in
:Aktualizacja
Wiele osób wspomina, że poprzednie metody nie zwracają nowego obiektu, a raczej działają na samym obiekcie. W związku z tym chciałem dodać inne rozwiązanie, które zwraca nowy obiekt i pozostawia oryginalny obiekt bez zmian:
Array.prototype.reduce
redukuje tablicę do pojedynczej wartości, nieco łącząc poprzednią wartość z bieżącą. Łańcuch jest inicjowany przez pusty obiekt{}
. Przy każdej iteracji nowy kluczmyObject
dodawany jest z podwójnym kluczem jako wartością.Aktualizacja
Dzięki nowym funkcjom ES6 istnieje bardziej elegancki sposób wyrażania
objectMap
.źródło
map
poprawnie, ponieważ nie robireturn
- jest nadużywająca,map
jakby byłaforEach
rozmową. Gdyby rzeczywiście tak zrobił,return myObject[value] * 2
to wynikiem byłaby tablica zawierająca podwojone oryginalne wartości, a nie obiekt zawierający oryginalne klucze z podwójnymi wartościami, przy czym te ostatnie byłyby wyraźnie tym, o co poprosił OP..reduce
przykład jest OK, ale IMHO wciąż jest daleko w tyle za wygodą a.map
dla Objects, ponieważ twoje.reduce
wywołanie zwrotne musi nie tylko pasować do tego.reduce
, co działa, ale także wymaga, abymyObject
były dostępne w zakresie leksykalnym. To ostatnie w szczególności uniemożliwia przekazanie odwołania do funkcji w wywołaniu zwrotnym, wymagając zamiast tego funkcji anonimowej w miejscu.Co powiesz na jedną linijkę z natychmiastowym przypisywaniem zmiennych w zwykłym JS ( ES6 / ES2015 )?
Wykorzystanie operatora rozkładania i obliczonej składni nazwy klucza :
jsbin
Inna wersja używająca redukcji:
jsbin
Pierwszy przykład jako funkcja:
jsbin
Jeśli chcesz odwzorować zagnieżdżony obiekt rekurencyjnie w funkcjonalnym stylu, możesz to zrobić w następujący sposób:
jsbin
Lub bardziej koniecznie:
jsbin
Od wersji ES7 / ES2016 możesz używać
Object.entries()
zamiastObject.keys()
np .:Wprowadzono ES2019
Object.fromEntries()
, który jeszcze bardziej upraszcza:Dziedziczone właściwości i łańcuch prototypów:
W niektórych rzadkich sytuacjach może być konieczne odwzorowanie obiektu podobnego do klasy, który posiada właściwości odziedziczonego obiektu w łańcuchu prototypów . W takich przypadkach
Object.keys()
nie będzie działać, ponieważObject.keys()
nie wylicza odziedziczonych właściwości. Jeśli potrzebujesz mapować odziedziczone właściwości, powinieneś użyćfor (key in myObj) {...}
.Oto przykład obiektu, który dziedziczy właściwości innego obiektu i jak
Object.keys()
nie działa w takim scenariuszu.jsbin
Wyświadcz mi jednak przysługę i unikaj dziedziczenia . :-)
źródło
Object.keys
nie wylicza odziedziczonych właściwości. Sugeruję dodanie ostrzeżenia.Object.entries({a: 1, b: 2, c: 3})
.(o, f)
obj
Object.assign(...Object.entries(obj).map(([k, v]) => ({[k]: v * v})))
nie działa, jeśliobj
jest pustym obiektem. Przejdź do:Object.assign({}, ...Object.entries(obj).map(([k, v]) => ({[k]: v * v})))
.Brak metod natywnych, ale lodash # mapValues wykona zadanie doskonale
źródło
Object.entries({a: 1, b: 2, c: 3})
aby uzyskać tablicę._.map()
aby otrzymać klucz jako drugi argument - zgodnie z wymaganiami PO.Łatwo jest napisać jeden:
z przykładowym kodem:
Uwaga: ta wersja pozwala również (opcjonalnie) ustawić
this
kontekst dla wywołania zwrotnego, podobnie jakArray
metoda.EDYCJA - zmieniono, aby usunąć użycie
Object.prototype
, aby upewnić się, że nie koliduje z żadną istniejącą właściwością nazwanąmap
na obiekcie.źródło
map
, ale muszę powiedzieć, że modyfikowanieObject.prototype
nie pasuje do mnie, nawet jeśli nie jest policzalne.Object.prototype
innego niż (teoretyczne) ryzyko kolizji z innymi metodami. FWIW, nie rozumiem, w jaki sposób druga odpowiedź zdobyła tyle głosów, ile ma, jest całkowicie błędna.o = {map: true, image: false}
. Jesteś narażając go po prostu napisaćo.map(fn)
zamiastmap(o,fn)
Możesz użyć,
Object.keys
a następnieforEach
nad zwróconą tablicą kluczy:Lub w bardziej modułowy sposób:
Zauważ, że
Object.keys
zwraca tablicę zawierającą tylko własne wyliczalne właściwości obiektu, dlatego zachowuje się jakfor..in
pętla zhasOwnProperty
czekiem.źródło
To proste bs i wszyscy w społeczności JS o tym wiedzą. Nie powinno być to funkcjonalność:
oto naiwne wdrożenie:
to bardzo denerwujące, że trzeba to cały czas wdrażać;)
Jeśli chcesz czegoś bardziej zaawansowanego, co nie koliduje z klasą Object, spróbuj tego:
ale można bezpiecznie dodać tę funkcję mapy do Object, po prostu nie dodawaj do Object.prototype.
źródło
Object
obiektu globalnego ? Wystarczyconst mapObject = (obj, fn) => { [...]; return ret; }
..map
jest ogólnie rozumiany jako interfejs Functor i nie ma jednej definicji Functora dla „Object”, ponieważ praktycznie wszystko w javascript może być Object, w tym rzeczy z własnymi bardzo wyraźnymi i zdefiniowanymi interfejsami / logiką .map.Przyszedłem tutaj, szukając odpowiedzi na mapowanie obiektu na tablicę i otrzymując odpowiedź. Jeśli przyszedłeś tutaj, szukając tej samej odpowiedzi, co ja, oto jak możesz zmapować i sprzeciwić się tablicy.
Możesz użyć map, aby zwrócić nową tablicę z obiektu w następujący sposób:
źródło
Object.values(myObject)
Przyjęta odpowiedź ma dwie wady:
Array.prototype.reduce
, ponieważ redukcja oznacza zmianę struktury typu złożonego, co nie zdarza się w tym przypadku.Podejście funkcjonalne ES6 / ES2015
Należy pamiętać, że wszystkie funkcje są zdefiniowane w formie curry.
o
zostaje przypisany ponownie. Ponieważ Javascript przekazuje wartości referencyjne poprzez udostępnienie ,o
generowana jest płytka kopia pliku . Jesteśmy teraz w stanie mutowaćo
wewnątrzomap
bez mutacjio
w zakresie nadrzędnym.map
wartość zwracana jest ignorowana, ponieważmap
wykonuje mutacjęo
. Ponieważ ten efekt uboczny utrzymuje sięomap
i nie jest widoczny w zakresie nadrzędnym, jest całkowicie akceptowalny.To nie jest najszybsze rozwiązanie, ale deklaratywne i wielokrotnego użytku. Oto ta sama implementacja, co w jednym wierszu, zwięzła, ale mniej czytelna:
Dodatek - dlaczego obiekty domyślnie nie są iterowalne?
ES2015 określił iterator i iterowalne protokoły. Ale obiekty wciąż nie są iterowalne, a zatem nie można ich zmapować. Powodem jest mieszanie danych i poziomu programu .
źródło
Array.prototype.reduce
. Wszystko, co chcę tutaj zilustrować, to to, że przyjęta odpowiedź w jakiś sposób „nadużywa”Array.prototype.reduce
i jak można zrealizować czysto funkcjonalne mapowanie. Jeśli nie jesteś zainteresowany programowaniem funkcjonalnym, po prostu zignoruj moją odpowiedź.fold
jest bardziej ogólne niżmap
(funktor). Taka była jednak moja wiedza z połowy 2016 r. To połowa wieczności: DJavaScript właśnie dostał nowy
Object.fromEntries
metodę.Przykład
Wyjaśnienie
Powyższy kod konwertuje Obiekt na zagnieżdżoną Array (
[[<key>,<value>], ...]
), którą można zamapować.Object.fromEntries
konwertuje tablicę z powrotem na obiekt.Fajną rzeczą w tym wzorze jest to, że możesz łatwo brać pod uwagę klucze obiektów podczas mapowania.
Dokumentacja
Object.fromEntries()
Object.entries()
Obsługa przeglądarki
Object.fromEntries
jest obecnie obsługiwany tylko przez te przeglądarki / silniki , niemniej dostępne są wielopełniacze (np. @ babel / polyfill ).źródło
Object.fromEntries
jest przeciwieństwemObject.entries
.Object.entries
konwertuje obiekt na listę par klucz-wartość.Object.fromEntries
konwertuje listę par klucz-wartość na obiekt.Wersja minimalna (es6):
źródło
Object.entries(obj).reduce((a, [k, v]) => [a[k] = v * v, a], {})
, nawiasy klamrowe zamiast nawiasów.Object.entries(obj).reduce((a, [k, v]) => {a[k] = v * v; return a}, {})
Object.entries().reduce
to najlepsze rozwiązanie, które myślę z ES6 +. Dostalibyśmy więcej głosów pozytywnych, gdyby użyłreturn
instrukcji w reduktorze zamiastimplicit return
icomma
operatora - co jest schludne, ale trudne do odczytania IMHODla maksymalnej wydajności.
Jeśli Twój obiekt nie zmienia się często, ale wymaga częstej iteracji, sugeruję użycie natywnej mapy jako pamięci podręcznej.
Object.entries już działa w Chrome, Edge, Firefox i Beta Opera, więc jest to funkcja przyszłościowa. Jest z ES7, więc polyfill to https://github.com/es-shims/Object.entries dla IE, gdzie to nie działa.
źródło
const fn = v => v * 2; const newObj = Object.entries(myObject).reduce((acc, [k,v]) => Object.assign({}, acc, {[k]: fn(v)}), {});
możesz użyć
map
metody iforEach
tablic, ale jeśli chcesz jej użyćObject
, możesz użyć jej z akcentem jak poniżej:Korzystanie z Javascript (ES6)
Korzystanie z jQuery
Lub możesz użyć innych pętli, takich jak
$.each
metoda, jak na poniższym przykładzie:źródło
$
jest jquery?map function
Nie istnieje naObject.prototype
jednak można naśladować go jak takźródło
typeof callback === 'function'
absolutnie zbędne. 1)map
nie ma znaczenia bez wywołania zwrotnego 2) jeślicallback
nie jest funkcją, twojamap
implementacja po prostu działa bez znaczenia dla pętli for. Ponadto,Object.prototype.hasOwnProperty.call( obj, key )
jest trochę przesadą.Natknąłem się na to jako pierwszy element w wyszukiwarce Google, próbując nauczyć się tego robić, i pomyślałem, że podzielę się, aby inni ludzie znaleźli to niedawno rozwiązanie, które znalazłem, które używa niezmiennego pakietu npm.
Myślę, że warto się nim dzielić, ponieważ niezmienny używa sytuacji DOKŁADNEJ OP w swojej własnej dokumentacji - poniższy kod nie jest moim własnym kodem, ale został pobrany z bieżącej dokumentacji immutable-js:
Nie chodzi o to, że Seq ma inne właściwości („Seq opisuje leniwą operację, umożliwiając im efektywne połączenie wszystkich metod gromadzenia wyższego rzędu (takich jak mapa i filtr) poprzez nie tworzenie pośrednich kolekcji”) oraz że niektóre inne dane niezmiennego js struktury mogą również wykonywać tę pracę dość skutecznie.
Każdy, kto użyje tej metody, będzie oczywiście musiał
npm install immutable
i może przeczytać dokumenty:https://facebook.github.io/immutable-js/
źródło
EDYCJA: Kanonicznym sposobem korzystania z nowszych funkcji JavaScript jest -
Gdzie
o
jest jakiś obiekt if
twoja funkcja mapowania. Lub możemy powiedzieć, biorąc pod uwagę funkcjęa -> b
i obiekt o wartościach typua
, produkujemy obiekt o wartościach typub
. Jako podpis pseudo-typowy -Oryginalna odpowiedź została napisana, aby zademonstrować potężny kombinator,
mapReduce
który pozwala nam myśleć o naszej transformacji w inny sposóbm
, mapowanie funkcja - daje szansę przekształcenia przychodzącego elementu przed…r
, funkcja redukująca - ta funkcja łączy akumulator z wynikiem zmapowanego elementuIntuicyjnie
mapReduce
tworzy nowy reduktor, do którego możemy podłączyć bezpośrednioArray.prototype.reduce
. Ale co ważniejsze, możemy implementować naszą implementację funktora obiektów womap
prosty sposób, wykorzystując obiekt monoidObject.assign
i{}
.Zauważ, że jedyną częścią programu, którą naprawdę musieliśmy napisać, jest sama implementacja mapowania -
Który mówi, biorąc pod uwagę znany przedmiot
o
, a niektóre kluczk
, budowy obiektu i którego właściwość obliczanak
jest wynikiem dzwoniącf
na wartości Kluczem jest,o[k]
.Możemy uzyskać wgląd
mapReduce
„s potencjał sekwencjonowania jeśli najpierw streszczenieoreduce
Wszystko działa tak samo, ale teraz
omap
można je zdefiniować na wyższym poziomie. Oczywiście noweObject.entries
sprawiają, że wygląda to głupio, ale ćwiczenie jest nadal ważne dla ucznia.Nie zobaczysz tutaj pełnego potencjału
mapReduce
, ale dzielę się tą odpowiedzią, ponieważ interesujące jest zobaczyć, ile miejsc można zastosować. Jeśli interesuje Cię sposób jej wyprowadzenia i inne sposoby, które mogą być przydatne, zapoznaj się z tą odpowiedzią .źródło
Map
iMap.entries
OK: D. Mam dość wykorzystywania zwykłych obiektów jako typów danych map.Map
powinienem być użyty tam, gdzie to możliwe, ale nie zastępuje to całkowicie potrzeby korzystania z tych procedur na zwykłych obiektach JS: DNa podstawie odpowiedzi @Amberlamps, oto funkcja narzędzia (jako komentarz wyglądał brzydko)
a zastosowanie to:
źródło
źródło
enumerable
domyślniefalse
Moja odpowiedź jest w dużej mierze oparta na najwyżej ocenianej odpowiedzi tutaj i mam nadzieję, że wszyscy rozumieją (mają to samo wytłumaczenie na moim GitHubie). Oto dlaczego jego impementacja mapą działa:
Celem tej funkcji jest pobranie obiektu i zmodyfikowanie oryginalnej zawartości obiektu za pomocą metody dostępnej dla wszystkich obiektów (zarówno obiektów, jak i tablic) bez zwracania tablicy. Prawie wszystko w JS jest przedmiotem i dlatego elementy znajdujące się w dalszej części procesu dziedziczenia mogą potencjalnie technicznie wykorzystać te dostępne dla osób znajdujących się powyżej linii (i na odwrót).
Powodem tego jest to, że funkcje .map zwracają tablicę WYMAGAJĄCĄ podania jawnego lub niejawnego RETURN tablicy zamiast po prostu modyfikowania istniejącego obiektu. Zasadniczo oszukasz program, aby pomyślał, że obiekt jest tablicą, używając Object.keys, który pozwoli ci korzystać z funkcji mapowania z działaniem na wartości, z którymi powiązane są poszczególne klucze (faktycznie przypadkowo zwróciłem tablice, ale je naprawiłem). Dopóki nie nastąpi zwrot w normalnym sensie, nie powstanie tablica z oryginalnym obiektem w stanie nienaruszonym i zmodyfikowanym zgodnie z zaprogramowaniem.
Ten konkretny program pobiera obiekt o nazwie obrazy i pobiera wartości jego kluczy oraz dołącza znaczniki URL do użycia w innej funkcji. Oryginał to:
... i zmodyfikowano to:
Oryginalna struktura obiektu pozostaje nienaruszona, umożliwiając normalny dostęp do właściwości, o ile nie ma zwrotu. NIE każ mu zwracać tablicy jak zwykle i wszystko będzie dobrze. Celem jest PONOWNE PRZYPISANIE oryginalnych wartości (obrazów [klucz]) do tego, co jest potrzebne, a nie do niczego innego. O ile mi wiadomo, aby zapobiec wyjściu z tablicy, MUSI BYĆ PRZEKAZANIE obrazów [klucz] i nie może być domniemana ani wyraźna prośba o zwrócenie tablicy (przypisanie zmiennej robi to i było dla mnie błędne).
EDYTOWAĆ:
Zajmę się jego drugą metodą dotyczącą tworzenia nowego obiektu, aby uniknąć modyfikacji oryginalnego obiektu (a ponowne przypisanie wydaje się być nadal konieczne, aby uniknąć przypadkowego utworzenia tablicy jako wyniku). Funkcje te używają składni strzałek i są przeznaczone, jeśli chcesz po prostu utworzyć nowy obiekt do wykorzystania w przyszłości.
Sposób działania tych funkcji jest następujący:
mapFn pobiera funkcję, która zostanie dodana później (w tym przypadku (wartość) => wartość) i po prostu zwraca wszystko, co jest tam zapisane, jako wartość dla tego klucza (lub pomnożona przez dwa, jeśli zmienisz wartość zwracaną tak jak on) w mapFn ( obj) [klucz],
a następnie redefiniuje pierwotną wartość powiązaną z kluczem w wyniku [klucz] = mapFn (obj) [klucz]
i zwraca operację wykonaną na wyniku (akumulator umieszczony w nawiasach zainicjowany na końcu funkcji redukcji).
Wszystko to jest wykonywane na wybranym obiekcie i JESZCZE NIE MOŻE być niejawnym żądaniem zwróconej tablicy i działa tylko przy ponownym przypisywaniu wartości, o ile wiem. Wymaga to gimnastyki umysłowej, ale zmniejsza liczbę wymaganych linii kodu, jak widać powyżej. Dane wyjściowe są dokładnie takie same, jak widać poniżej:
Pamiętaj, że działało to z NIE-LICZBAMI. MOŻESZ zduplikować KAŻDY obiekt, PO PROSTU POWRACAJĄCĄ WARTOŚĆ w funkcji mapFN.
źródło
Pierwsza funkcja odpowiada na pytanie. Tworzy mapę.
Druga funkcja nie tworzy mapy. Zamiast tego używa pętli przez właściwości w istniejącym obiekcie za pomocą
hasOwnProperty()
. Ta mapa alternatywna może być lepszym rozwiązaniem w niektórych sytuacjach.źródło
Jeśli interesuje Cię
map
ping nie tylko wartości, ale także klucze, napisałemObject.map(valueMapper, keyMapper)
, że zachowuje się w ten sposób:źródło
npm install @mattisg/object.map
.Potrzebowałem wersji, która pozwoliła również modyfikować klucze (na podstawie odpowiedzi @Amberlamps i @yonatanmn);
factObject =
Edycja: niewielka zmiana do przekazania w obiekcie początkowym {}. Pozwala to na [] (jeśli klucze są liczbami całkowitymi)
źródło
W szczególności chciałem użyć tej samej funkcji, której użyłem do tablic dla pojedynczego obiektu, i chciałem, aby było to proste. To działało dla mnie:
źródło
var mapped = myMapFunction(item)
Aby ściślej odpowiedzieć na to, o co dokładnie poprosił PO, PO chce obiektu:
mieć metodę mapy
myObject.map
,Imho najlepszy (mierzone na „ bliskie temu, co jest proszony ” + „No es {5,6,7} wymagane niepotrzebnie”) odpowiedź byłaby:
Powyższy kod unika celowego używania jakichkolwiek funkcji językowych, dostępnych tylko w najnowszych edycjach ECMAScript. Dzięki powyższemu kodowi problem można rozwiązać, np .:
Oprócz tego, że niektórzy czują się niezadowoleni, istnieje możliwość wstawienia rozwiązania do takiego łańcucha prototypów.
Coś, co przy dokładnym nadzorze nie powinno mieć żadnych złych skutków i nie powinno wpływać na
map
metodę innych obiektów (np. Macierzymap
).źródło
Najpierw przekonwertuj HTMLCollection za pomocą Object.entries (kolekcja). Następnie jest iterowalny, możesz teraz użyć na nim metody .map.
odniesienie https://medium.com/@js_tut/calling-javascript-code-on-multiple-div-elements-without-the-id-attribute-97ff6a50f31
źródło
Zdefiniuj funkcję mapEntries.
mapEntries przyjmuje funkcję wywołania zwrotnego, która jest wywoływana przy każdym wpisie w obiekcie z wartościami parametrów, kluczem i obiektem. Powinien zwrócić nową wartość.
mapEntries powinien zwrócić nowy obiekt z nowymi wartościami zwróconymi z wywołania zwrotnego.
Edycja: poprzednia wersja nie określała, że nie jest to właściwość wyliczalna
źródło
Hej, napisałem małą funkcję mapera, która może pomóc.
źródło
Innym podejściem jest użycie niestandardowej funkcji strunowania json, która może również działać na głębokich obiektach. Może to być przydatne, jeśli zamierzasz opublikować go na serwerze jako json
źródło
Obsługuję tylko ciągi znaków w celu ograniczenia wyjątków:
źródło
Mapowanie obiektów w TypeScript
Lubię przykłady, które wykorzystują
Object.fromEntries
takie jak ten , ale nadal nie są one łatwe w użyciu. Odpowiedzi, które wykorzystują,Object.keys
a następnie sprawdzają, wkey
rzeczywistości wykonują wiele przeglądów, które mogą nie być konieczne.Chciałem tam była
Object.map
funkcja, ale możemy tworzyć własne i nazywają toobjectMap
z możliwością modyfikacji zarównokey
avalue
:Użycie (JavaScript):
Kod (TypeScript):
Jeśli nie używasz TypeScript, skopiuj powyższy kod do TypeScript Playground, aby uzyskać kod JavaScript.
Również powodem kładę
keySelector
povalSelector
liście parametrów, ponieważ jest to opcjonalne.* Niektóre podziękowania należą się odpowiedzi Aleksandra Millsa .
źródło
Ta funkcja przechodzi rekurencyjnie przez obiekt i tablice obiektów. Atrybuty można usunąć, jeśli zostaną zwrócone niezdefiniowane
źródło