Eu tenho um objeto:
myObject = { 'a': 1, 'b': 2, 'c': 3 }
Estou procurando um método nativo, semelhante ao Array.prototype.map
que seria usado da seguinte maneira:
newObject = myObject.map(function (value, label) {
return value * value;
});
// newObject is now { 'a': 1, 'b': 4, 'c': 9 }
O JavaScript tem essa map
função para objetos? (Quero isso para o Node.JS, para não me importar com problemas entre navegadores.)
javascript
node.js
functional-programming
map-function
Randomblue
fonte
fonte
Object.keys
, que não tem nenhuma ordem bem definida. Isso pode ser problemático, sugiro usarObject.getOwnPropertyNames
.Object.keys
eObject.getOwnPropertyNames
. Veja developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/…Object.keys
depende da implementação. Veja stackoverflow.com/a/30919039/1529630Respostas:
Não há nativo
map
para oObject
objeto, mas e quanto a isso:Mas você pode facilmente iterar sobre um objeto usando
for ... in
:Atualizar
Muitas pessoas estão mencionando que os métodos anteriores não retornam um novo objeto, mas operam no próprio objeto. Para esse assunto, eu queria adicionar outra solução que retorne um novo objeto e deixe o objeto original como ele é:
Array.prototype.reduce
reduz uma matriz para um único valor, mesclando um pouco o valor anterior com o atual. A cadeia é inicializada por um objeto vazio{}
. Em cada iteração, uma nova chavemyObject
é adicionada com o dobro da chave como valor.Atualizar
Com os novos recursos do ES6, há uma maneira mais elegante de se expressar
objectMap
.fonte
map
corretamente porque não está fazendo umreturn
- está abusandomap
como se fosse umaforEach
chamada. Se ele realmente o fizessereturn myObject[value] * 2
, o resultado seria uma matriz contendo os valores originais duplicados, em vez de um objeto contendo as chaves originais com valores duplicados, sendo o último claramente o que o OP solicitava..reduce
exemplo é bom, mas IMHO ainda está muito longe da conveniência de um.map
para objetos, já que seu.reduce
retorno de chamada não apenas precisa corresponder à maneira que.reduce
funciona, mas também exige quemyObject
esteja disponível no escopo lexical. O último, em particular, torna impossível passar apenas uma referência de função no retorno de chamada, exigindo uma função anônima no local.Que tal um liner com atribuição imediata de variável em JS simples ( ES6 / ES2015 )?
Utilizando o operador spread e a sintaxe do nome da chave computada :
jsbin
Outra versão usando reduzir:
jsbin
Primeiro exemplo como uma função:
jsbin
Se você deseja mapear um objeto aninhado recursivamente em um estilo funcional , isso pode ser feito da seguinte maneira:
jsbin
Ou mais imperativamente, assim:
jsbin
Desde o ES7 / ES2016, você pode usar em
Object.entries()
vez de,Object.keys()
por exemplo, o seguinte:Introduzido o ES2019
Object.fromEntries()
, que simplifica ainda mais isso:Propriedades herdadas e a cadeia de protótipos:
Em uma situação rara, pode ser necessário mapear um objeto de classe que contém propriedades de um objeto herdado em sua cadeia de protótipos . Nesses casos
Object.keys()
, não funcionará, porqueObject.keys()
não enumera propriedades herdadas . Se você precisar mapear propriedades herdadas , usefor (key in myObj) {...}
.Aqui está um exemplo de um objeto que herda as propriedades de outro objeto e como
Object.keys()
não funciona nesse cenário.jsbin
No entanto, faça-me um favor e evite a herança . :-)
fonte
Object.keys
não enumerar propriedades herdadas. Eu sugiro que você adicione um aviso.Object.entries({a: 1, b: 2, c: 3})
.(o, f)
como argumentos, mas usaobj
no corpo.Object.assign(...Object.entries(obj).map(([k, v]) => ({[k]: v * v})))
não funciona seobj
for um objeto vazio. Mudar para:Object.assign({}, ...Object.entries(obj).map(([k, v]) => ({[k]: v * v})))
.Nenhum método nativo, mas o lodash # mapValues fará o trabalho de maneira brilhante
fonte
Object.entries({a: 1, b: 2, c: 3})
para obter uma matriz._.map()
para obter a chave como o segundo argumento - conforme exigido pelo OP._.mapValues()
também fornece a chave como o segundo argumento. Também_.map()
não funcionaria aqui, pois apenas retorna matrizes, não objetos:_.map({ 'a': 1, 'b': 2, 'c': 3}, n => n * 3) // [3, 6, 9]
É muito fácil escrever um:
com código de exemplo:
Nota: esta versão também permite definir (opcionalmente) o
this
contexto do retorno de chamada, assim como oArray
método.EDIT - alterado para remover o uso de
Object.prototype
, para garantir que não colidir com nenhuma propriedade existente nomeadamap
no objeto.fonte
map
, mas devo dizer que a modificaçãoObject.prototype
não se encaixa bem comigo, mesmo que não seja enumerável.Object.prototype
o risco (teórico) de colisão com outros métodos. FWIW, eu não consigo entender como a outra resposta conseguiu tantos votos quanto ela tem, está completamente errado.o = {map: true, image: false}
. Você está arriscando apenas para escrevero.map(fn)
, em vez demap(o,fn)
Você pode usar
Object.keys
e, em seguida,forEach
sobre a matriz de chaves retornada:Ou de uma forma mais modular:
Observe que
Object.keys
retorna uma matriz que contém apenas as propriedades enumeráveis do objeto, portanto, ele se comporta como umfor..in
loop com umahasOwnProperty
verificação.fonte
Isso é bs direto, e todos na comunidade JS sabem disso. Não deve ser essa funcionalidade:
aqui está a implementação ingênua:
é super chato ter que implementar isso você mesmo o tempo todo;)
Se você deseja algo um pouco mais sofisticado, que não interfira na classe Object, tente o seguinte:
mas é seguro adicionar essa função de mapa a Object, apenas não adicione a Object.prototype.
fonte
Object
objeto global ? Apenas tenhaconst mapObject = (obj, fn) => { [...]; return ret; }
..map
geralmente é entendida como uma interface do Functor, e não existe uma definição única do Functor para "Objeto" porque praticamente qualquer coisa em javascript pode ser um Objeto, incluindo itens com interfaces / lógica .map muito distintas e definidas.Eu vim aqui procurando encontrar e responder para mapear um objeto para uma matriz e obtive esta página como resultado. Caso você tenha vindo aqui procurando a mesma resposta que eu, aqui está como você pode mapear e objetar a uma matriz.
Você pode usar o mapa para retornar uma nova matriz do objeto da seguinte maneira:
fonte
Object.values(myObject)
A resposta aceita tem duas desvantagens:
Array.prototype.reduce
, porque reduzir significa alterar a estrutura de um tipo composto, o que não acontece neste caso.Uma abordagem funcional ES6 / ES2015
Observe que todas as funções são definidas na forma de caril.
o
é reatribuída. Como o Javascript passa valores de referência compartilhando , uma cópia superficialo
é gerada. Agora, somos capazes de fazer uma mutaçãoo
internaomap
sem alteraro
o escopo pai.map
, o valor de retorno é ignorado, porquemap
executa uma mutação deo
. Como esse efeito colateral permanece dentroomap
e não é visível no escopo pai, é totalmente aceitável.Esta não é a solução mais rápida, mas declarativa e reutilizável. Aqui está a mesma implementação que uma linha, sucinta mas menos legível:
Adendo - por que os objetos não são iteráveis por padrão?
O ES2015 especificou o iterador e os protocolos iteráveis. Mas os objetos ainda não são iteráveis e, portanto, não podem ser mapeados. O motivo é a mistura de dados e nível do programa .
fonte
Array.prototype.reduce
. Tudo o que quero ilustrar aqui é que a resposta aceita de alguma forma "abusa"Array.prototype.reduce
e como um mapeamento puramente funcional pode ser implementado. Se você não está interessado em programação funcional, ignore minha resposta.fold
é mais genérico que ummap
(functor). No entanto, esse foi meu conhecimento desde meados de 2016. Isso é meia eternidade: DO JavaScript acabou de receber o novo
Object.fromEntries
método.Exemplo
Explicação
O código acima converte o objeto em uma matriz aninhada (
[[<key>,<value>], ...]
) na qual você pode mapear.Object.fromEntries
converte a matriz de volta em um objeto.O legal desse padrão é que agora você pode facilmente levar em consideração as chaves do objeto durante o mapeamento.
Documentação
Object.fromEntries()
Object.entries()
Suporte do navegador
Object.fromEntries
atualmente é suportado apenas por esses navegadores / mecanismos , no entanto, existem polyfills disponíveis (por exemplo, @ babel / polyfill ).fonte
Object.fromEntries
é o oposto deObject.entries
.Object.entries
converte um objeto em uma lista de pares de valores-chave.Object.fromEntries
converte uma lista de pares de valores-chave em um objeto.Versão mínima (es6):
fonte
Object.entries(obj).reduce((a, [k, v]) => [a[k] = v * v, a], {})
, colchetes angulares em vez de parênteses.Object.entries(obj).reduce((a, [k, v]) => {a[k] = v * v; return a}, {})
Object.entries().reduce
é a melhor solução que eu acho que com ES6 + .Pretende obter mais upvotes se ele usou umareturn
declaração no redutor em vez deimplicit return
ecomma
operador - que é limpo, mas difícil de ler IMHOPara desempenho máximo.
Se o seu objeto não muda frequentemente, mas precisa ser repetido com frequência, sugiro usar um mapa nativo como cache.
Object.entries já funciona no Chrome, Edge, Firefox e beta Opera, por isso é um recurso à prova de futuro. É do ES7, então preencha o https://github.com/es-shims/Object.entries para o IE, onde não funciona.
fonte
const fn = v => v * 2; const newObj = Object.entries(myObject).reduce((acc, [k,v]) => Object.assign({}, acc, {[k]: fn(v)}), {});
você pode usar o
map
método e asforEach
matrizes, mas se quiser usá-Object
lo, use-o com o twist abaixo:Usando Javascript (ES6)
Usando jQuery
Ou você pode usar outros loops também como
$.each
método, como no exemplo abaixo:fonte
$
está o jquery?O
map function
não existe noObject.prototype
entanto, você pode emular assimfonte
typeof callback === 'function'
absolutamente redundante. 1)map
não tem significado sem retorno de chamada 2) secallback
não estiver funcionando, suamap
implementação executa apenas um loop for sem sentido. Além disso,Object.prototype.hasOwnProperty.call( obj, key )
é um pouco exagerado.Encontrei isso como um primeiro item em uma pesquisa no Google tentando aprender a fazer isso, e pensei em compartilhar com outros foliões que encontrassem isso recentemente a solução que encontrei, que usa o pacote npm imutável.
Acho interessante compartilhar porque o imutável usa a situação EXATA do OP em sua própria documentação - o seguinte não é meu próprio código, mas extraído da documentação atual do immutable-js:
Não que o Seq tenha outras propriedades ("O Seq descreve uma operação lenta, permitindo que eles encadeiem com eficiência o uso de todos os métodos de coleta de ordem superior (como mapa e filtro), não criando coleções intermediárias") e que alguns outros dados immutable-js estruturas também podem fazer o trabalho com bastante eficiência.
Qualquer pessoa que use esse método precisará, é claro,
npm install immutable
e poderá querer ler os documentos:https://facebook.github.io/immutable-js/
fonte
EDIT: A maneira canônica de usar os recursos mais recentes do JavaScript é:
Onde
o
está algum objeto ef
é sua função de mapeamento. Ou podemos dizer que, dada uma função dea -> b
e um objeto com valores de tipoa
, produza um objeto com valores de tipob
. Como uma assinatura pseudo-tipo -A resposta original foi escrita para demonstrar um poderoso combinador,
mapReduce
que nos permite pensar em nossa transformação de uma maneira diferentem
, a função de mapeamento - permite transformar o elemento recebido antes de…r
, a função redutora - essa função combina o acumulador com o resultado do elemento mapeadoIntuitivamente,
mapReduce
cria um novo redutor ao qual podemos conectar diretamenteArray.prototype.reduce
. Porém, mais importante, podemos implementar nossa implementação de functor de objetoomap
claramente, utilizando o objeto monóide,Object.assign
e{}
.Observe que a única parte do programa que realmente tivemos que escrever é a própria implementação de mapeamento -
O que diz que, dado um objeto conhecido
o
e alguma chavek
, construa um objeto e cuja propriedade calculadak
seja o resultado da chamadaf
do valor da chave,o[k]
,.Temos um vislumbre do
mapReduce
potencial de seqüenciamento se abstraímosoreduce
Tudo funciona da mesma forma, mas
omap
pode ser definido em um nível superior agora. Claro que o novoObject.entries
faz com que isso pareça bobo, mas o exercício ainda é importante para o aluno.Você não verá todo o potencial
mapReduce
daqui, mas eu compartilho esta resposta, porque é interessante ver quantos lugares ela pode ser aplicada. Se você estiver interessado em saber como é derivado e de que outras maneiras poderia ser útil, consulte esta resposta .fonte
Map
eMap.entries
, OK: D. Estou cansado de abusar de objetos simples como tipos de dados do mapa.Map
deve ser usado onde / quando possível, mas não substitui totalmente a necessidade de usar estes procedimentos em objetos JS simples, embora tho: DCom base na resposta @Amberlamps, aqui está uma função de utilitário (como um comentário, parecia feio)
e o uso é:
fonte
fonte
enumerable
o padrão éfalse
Minha resposta é amplamente baseada na resposta mais alta classificada aqui e espero que todos entendam (tenha a mesma explicação no meu GitHub também). É por isso que sua impementação com o mapa funciona:
O objetivo da função é pegar um objeto e modificar o conteúdo original do objeto usando um método disponível para todos os objetos (objetos e matrizes) sem retornar uma matriz. Quase tudo no JS é um objeto e, por esse motivo, os elementos mais abaixo no pipeline de herança podem potencialmente usar tecnicamente aqueles disponíveis para os que estão na linha de frente (e o inverso aparece).
O motivo disso funcionar é que as funções .map retornam uma matriz, EXIGINDO que você forneça um RETURN explícito ou implícito de uma matriz, em vez de simplesmente modificar um objeto existente. Você basicamente engana o programa para pensar que o objeto é uma matriz usando Object.keys, que permitirá que você use a função map com sua atuação nos valores aos quais as chaves individuais estão associadas (na verdade, retornei acidentalmente matrizes, mas a corrigi). Enquanto não houver retorno no sentido normal, não haverá matriz criada com o objeto original ainda intacto e modificado conforme programado.
Esse programa específico pega um objeto chamado images e pega os valores de suas chaves e anexa tags de URL para uso em outra função. Original é este:
... e modificado é este:
A estrutura original do objeto é deixada intacta, permitindo o acesso normal à propriedade, desde que não haja retorno. NÃO faça com que ele retorne uma matriz como normal e tudo ficará bem. O objetivo é reatribuir os valores originais (imagens [chave]) ao que se deseja e não a mais nada. Até onde eu sei, para impedir a saída da matriz, TEM DE SER REASSIGNAMENTO de imagens [chave] e nenhuma solicitação implícita ou explícita para retornar uma matriz (a atribuição de variáveis faz isso e estava sendo repetida para mim).
EDITAR:
Indo abordar seu outro método em relação à criação de novos objetos para evitar modificar o objeto original (e a reatribuição parece ainda ser necessária para evitar a criação acidental de uma matriz como saída). Essas funções usam sintaxe de seta e existem se você simplesmente deseja criar um novo objeto para uso futuro.
A maneira como essas funções funcionam é assim:
mapFn pega a função a ser adicionada mais tarde (neste caso (valor) => valor) e simplesmente retorna o que estiver armazenado como um valor para essa chave (ou multiplicado por dois se você alterar o valor de retorno como ele fez) em mapFn ( obj) [chave],
e redefine o valor original associado à chave no resultado [chave] = mapFn (obj) [chave]
e retorna a operação executada no resultado (o acumulador localizado nos colchetes iniciado no final da função .reduce).
Tudo isso está sendo realizado no objeto escolhido e AINDA NÃO PODE haver uma solicitação implícita para uma matriz retornada e só funciona ao reatribuir valores, tanto quanto eu sei. Isso requer alguma ginástica mental, mas reduz as linhas de código necessárias, como pode ser visto acima. A saída é exatamente a mesma que pode ser vista abaixo:
Lembre-se de que isso funcionou com NÃO-NÚMEROS. Você pode duplicar QUALQUER objeto simplesmente retornando o valor na função mapFN.
fonte
A primeira função responde à pergunta. Cria um mapa.
A segunda função não cria um mapa. Em vez disso, ele percorre as propriedades no objeto existente usando
hasOwnProperty()
. Essa alternativa de mapa pode ser uma solução melhor em algumas situações.fonte
Se você está interessado em
map
executar ping, não apenas valores, mas também chaves, escreviObject.map(valueMapper, keyMapper)
, que se comportam desta maneira:fonte
npm install @mattisg/object.map
.Eu precisava de uma versão que permitisse modificar as chaves também (com base nas respostas @Amberlamps e @yonatanmn);
factObject =
Editar: leve alteração para passar no objeto inicial {}. Permite que seja [] (se as chaves forem números inteiros)
fonte
Eu queria especificamente usar a mesma função que estava usando para matrizes para um único objeto e queria mantê-lo simples. Isso funcionou para mim:
fonte
var mapped = myMapFunction(item)
Para responder mais de perto ao que precisamente o OP solicitou, o OP deseja um objeto:
ter um método de mapa
myObject.map
,A melhor resposta imho (medida em termos de " próximo ao que é solicitado " + "sem ES {5,6,7} necessário desnecessariamente") seria:
O código acima evita o uso intencional de qualquer recurso de idioma, disponível apenas nas edições recentes do ECMAScript. Com o código acima, o problema pode ser resolvido como:
Além de desaprovado por alguns, seria uma possibilidade de inserir a solução na cadeia de protótipos dessa maneira.
Algo que, quando feito com uma supervisão cuidadosa, não deve ter efeitos negativos e não afetar o
map
método de outros objetos (por exemplo, os de Arraymap
).fonte
Primeiro, converta sua HTMLCollection usando Object.entries (coleção). Então é uma iterável, agora você pode usar o método .map nele.
referência https://medium.com/@js_tut/calling-javascript-code-on-multiple-div-elements-without-the-id-attribute-97ff6a50f31
fonte
Defina uma função mapEntries.
mapEntries usa uma função de retorno de chamada que é chamada em cada entrada no objeto com o valor dos parâmetros, chave e objeto. Ele deve retornar um novo valor.
mapEntries deve retornar um novo objeto com os novos valores retornados do retorno de chamada.
Editar: uma versão anterior não especificou que esta não é uma propriedade enumerável
fonte
Hey escreveu uma pequena função de mapeador que pode ajudar.
fonte
Uma abordagem diferente é usar uma função customizada json stringify que também pode funcionar em objetos profundos. Isso pode ser útil se você pretende publicá-lo no servidor de qualquer maneira, como json
fonte
Eu manuseio apenas cadeias de caracteres para reduzir isenções:
fonte
Mapeador de objetos em TypeScript
Eu gosto dos exemplos que usam
Object.fromEntries
como este , mas ainda assim, eles não são muito fáceis de usar. As respostas que usamObject.keys
e pesquisam nakey
verdade estão fazendo várias pesquisas que podem não ser necessárias.Eu gostaria que houvesse uma
Object.map
função, mas podemos criar a nossa e chamá-laobjectMap
com a capacidade de modificar ambaskey
evalue
:Uso (JavaScript):
Código (TypeScript):
Se você não estiver usando o TypeScript, copie o código acima no TypeScript Playground para obter o código JavaScript.
Além disso, o motivo que eu coloquei
keySelector
depoisvalSelector
na lista de parâmetros é porque é opcional.* Alguns créditos vão para a resposta de alexander-mills .
fonte
Essa função percorre recursivamente o objeto e as matrizes de objetos. Os atributos podem ser excluídos se retornados indefinidos
fonte