2012-06-11 3 views
9

Czy nie ma wszechobecnej/standardowej funkcji JavaScript lub Coffeescript, która przekształca wartości obiektu/mapy/hasha?Jakakolwiek funkcja `map` Javascript lub Coffeescript, która przekształca wartości * obiektu *?

jQuery has $.map ale produkuje tylko Array.
Underscore has _.map ale produkuje również tylko Array.

Dla jasności, taka funkcja jest tym, czego szukam. (Ten przykład jest napisany w coffeescript nie Javascript.)

# Transforms the values in a map. (Doesn't modify `obj` — returns a new map.) 
# Example usage: 
# mapObjVals({ a: 'aa', b: 'bb'}, (key, value) -> value + '_!') 
# --> { a: 'aa_!', b: 'bb_!' } 
mapObjVals = (obj, f) -> 
    obj2 = {} 
    for k, v of obj 
    obj2[k] = f k, v 
    obj2 
+1

Wygląda na to, że odpowiedziałeś na własne pytanie :) Upewnij się, że używasz 'for own k, v of obj', aby zapobiec byciu przez prototypowe rozszerzenia. Chciałbym użyć pętli 'for' bezpośrednio zamiast funkcji pomocnika, ponieważ jest to rzadkość. –

Odpowiedz

6

Jeśli chcesz mapować obiektu do obiektu, trzeba użyć fold (tradycyjnej terminologii funkcjonalny) lub reduce (wspólne nowoczesną nazwę, używany przez podkreślenia), która buduje nową wartość z kolekcji:

_.reduce(obj, function(newObj, thisValue, thisKey) { 
     // modify newObj based on thisKey/thisValue 
     return newObj; 
     }, {}) 

funkcja przekazywana jako drugi argument jest wywoływana raz na parę klucz/wartość. Jest on przekazywany w budowanym obiekcie jako pierwszy argument, po którym następuje bieżąca wartość, a następnie powiązany klucz. Do funkcji można zmodyfikować obiekt i zwrócić jego nową wartość.

Trzecim argumentem dla _.reduce jest wartość początkowa nowego obiektu, która ma zostać przekazana pierwszej parze klucz/wartość; w tym przypadku jest to pusty obiekt/mapa/hash {}.

Reduce/fold/inject jest powszechnie używany do sumowania wartości. Zasadniczo za każdym razem, gdy chcesz utworzyć nową pojedynczą wartość z kolekcji. map to naprawdę tylko specjalny przypadek reduce, gdzie rzekomo zmniejszona wartość to naprawdę kolejna kolekcja o tym samym rozmiarze co oryginał.

Dla CoffeeScript, AFAIK, listy zawsze zwracają listy, nawet podczas iteracji nad obiektem. Możesz więc zajrzeć do the CoffeeScript version of Underscore.

+0

Dzięki! Mój przykład '+ '_!'' Działa na '_.reduce': _ _ ({a: 'aa', b: 'bb'}). Reduce ((memo, value, index) -> memo [index] = value + '_!'; memo), {} ' – KajMagnus

+1

" Niestety ", z' _.reduce', muszę 1) zwrócić 'memo' z wnętrza iteratora i 2) przekazać' { } 'to' reduce'. Więc jest nieco bardziej gadatliwy. Właściwie to moja przykładowa funkcja jest łatwiejsza do zrozumienia - gdy czytam 'mapObjVals ({a: 'aa', b: 'bb'}, (klucz, wartość) -> wartość + '_!')' Rozumiem dość szybko co zostało zrobione. – KajMagnus

+0

Tak, redukcja jest bardziej gadatliwa, ponieważ jest bardziej ogólna; mapa może być łatwo zaimplementowana pod względem redukcji. Czy masz potrzebę napisania funkcji pomocnika, aby ukryć tę gadatliwość, zależy od osobistych preferencji. –