J'ai un objet:
myObject = { 'a': 1, 'b': 2, 'c': 3 }
Je recherche une méthode native, similaire à Array.prototype.map
celle qui serait utilisée comme suit:
newObject = myObject.map(function (value, label) {
return value * value;
});
// newObject is now { 'a': 1, 'b': 4, 'c': 9 }
JavaScript a-t-il une telle map
fonction pour les objets? (Je veux cela pour Node.JS, donc je ne me soucie pas des problèmes inter-navigateurs.)
javascript
node.js
functional-programming
map-function
Randomblue
la source
la source
Object.keys
, qui n'a pas d'ordre bien défini. Cela peut être problématique, je suggère d'utiliser à laObject.getOwnPropertyNames
place.Object.keys
etObject.getOwnPropertyNames
. Voir developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…Object.keys
dépend de l'implémentation. Voir stackoverflow.com/a/30919039/1529630Réponses:
Il n'y a pas de natif
map
de l'Object
objet, mais qu'en est-il:Mais vous pouvez facilement parcourir un objet en utilisant
for ... in
:Mise à jour
Beaucoup de gens mentionnent que les méthodes précédentes ne retournent pas un nouvel objet, mais opèrent plutôt sur l'objet lui-même. D'ailleurs, je voulais ajouter une autre solution qui renvoie un nouvel objet et laisse l'objet d'origine tel qu'il est:
Array.prototype.reduce
réduit un tableau à une seule valeur en fusionnant quelque peu la valeur précédente avec le courant. La chaîne est initialisée par un objet vide{}
. À chaque itération, une nouvelle clé demyObject
est ajoutée avec deux fois la clé comme valeur.Mise à jour
Avec les nouvelles fonctionnalités ES6, il existe une manière plus élégante d'exprimer
objectMap
.la source
map
correctement parce qu'elle ne fait pasreturn
- elle abusemap
comme si c'était unforEach
appel. S'il le faisait réellement ,return myObject[value] * 2
le résultat serait un tableau contenant les valeurs d'origine doublées, au lieu d'un objet contenant les clés d'origine avec des valeurs doublées, ces dernières étant clairement ce que l'OP demandait..reduce
exemple est OK, mais à mon humble avis , il est encore loin de la commodité d'un.map
pour les objets, car votre.reduce
rappel doit non seulement correspondre à la façon dont cela.reduce
fonctionne, mais nécessite également qu'ilmyObject
soit disponible dans la portée lexicale. Ce dernier en particulier rend impossible de simplement passer une référence de fonction dans le rappel, nécessitant à la place une fonction anonyme sur place..map
n'est pas la méthode appropriée à utiliser lorsque vous n'allez pas utiliser le tableau mappé résultant - si vous ne voulez que des effets secondaires, comme dans votre premier code, vous devriez certainement l'utiliser à laforEach
place.Que diriez-vous d'un liner avec affectation variable immédiate en JS ordinaire ( ES6 / ES2015 )?
Utilisation de l' opérateur d'étalement et de la syntaxe du nom de clé calculé :
jsbin
Une autre version utilisant réduire:
jsbin
Premier exemple en fonction:
jsbin
Si vous souhaitez mapper un objet imbriqué récursivement dans un style fonctionnel , cela peut être fait comme ceci:
jsbin
Ou plus impérativement, comme ceci:
jsbin
Depuis ES7 / ES2016, vous pouvez utiliser
Object.entries()
au lieu deObject.keys()
par exemple comme ceci:ES2019 introduit
Object.fromEntries()
, ce qui simplifie encore plus ceci:Propriétés héritées et chaîne de prototypes:
Dans certaines situations rares, vous devrez peut-être mapper un objet de type classe qui détient les propriétés d'un objet hérité sur sa chaîne de prototype . Dans de tels cas
Object.keys()
, ne fonctionnera pas, carObject.keys()
n'énumère pas les propriétés héritées . Si vous devez mapper des propriétés héritées , vous devez utiliserfor (key in myObj) {...}
.Voici un exemple d'un objet qui hérite des propriétés d'un autre objet et comment
Object.keys()
ne fonctionne pas dans un tel scénario.jsbin
Cependant, faites-moi plaisir et évitez l' héritage . :-)
la source
Object.keys
n'énumère pas les propriétés héritées. Je vous suggère d'ajouter un avertissement.Object.entries({a: 1, b: 2, c: 3})
.(o, f)
arguments mais utilisezobj
dans le corps.Object.assign(...Object.entries(obj).map(([k, v]) => ({[k]: v * v})))
ne fonctionne pas s'ilobj
s'agit d'un objet vide. Changer à:Object.assign({}, ...Object.entries(obj).map(([k, v]) => ({[k]: v * v})))
.Pas de méthodes natives, mais lodash # mapValues fera le travail avec brio
la source
Object.entries({a: 1, b: 2, c: 3})
pour obtenir un tableau._.map()
pour obtenir la clé comme deuxième argument - comme requis par l'OP._.mapValues()
fournit également la clé comme deuxième argument. Aussi_.map()
ne fonctionnerait pas ici car il ne retourne que les tableaux, pas des objets:_.map({ 'a': 1, 'b': 2, 'c': 3}, n => n * 3) // [3, 6, 9]
Il est assez facile d'en écrire un:
avec un exemple de code:
NB: cette version vous permet également de (éventuellement) définir le
this
contexte du rappel, tout comme laArray
méthode.EDIT - modifié pour supprimer l'utilisation de
Object.prototype
, afin de s'assurer qu'il ne se heurte à aucune propriété existante nomméemap
sur l'objet.la source
map
, mais je dois dire que la modificationObject.prototype
ne me convient pas, même si elle n'est pas énumérable.Object.prototype
autre que le risque (théorique) de collision avec d'autres méthodes. FWIW, je ne peux pas comprendre comment l'autre réponse a obtenu autant de votes qu'elle a, c'est complètement faux.o = {map: true, image: false}
. Vous risquer juste pour écrire auo.map(fn)
lieu demap(o,fn)
Vous pouvez utiliser
Object.keys
puisforEach
sur le tableau de clés retourné:Ou de façon plus modulaire:
Notez que
Object.keys
renvoie un tableau contenant uniquement les propres propriétés énumérables de l'objet, donc il se comporte comme unefor..in
boucle avec unehasOwnProperty
vérification.la source
C'est bs, et tout le monde dans la communauté JS le sait. Il devrait y avoir cette fonctionnalité:
voici l'implémentation naïve:
c'est super ennuyeux d'avoir à implémenter ça tout le temps;)
Si vous voulez quelque chose d'un peu plus sophistiqué, qui n'interfère pas avec la classe Object, essayez ceci:
mais il est sûr d'ajouter cette fonction de carte à Object, ne l'ajoutez pas à Object.prototype.
la source
Object
objet global ? Justeconst mapObject = (obj, fn) => { [...]; return ret; }
..map
est généralement compris comme une interface Functor, et il n'y a pas de définition unique de Functor pour "Objet" car pratiquement tout ce qui est en javascript peut être un Objet, y compris des choses avec leurs propres interfaces / logiques .map très distinctes et définies.Je suis venu ici pour trouver et répondre pour mapper un objet sur un tableau et j'ai obtenu cette page en conséquence. Si vous êtes venu ici à la recherche de la même réponse que moi, voici comment vous pouvez mapper et vous opposer à un tableau.
Vous pouvez utiliser map pour renvoyer un nouveau tableau à partir de l'objet comme ceci:
la source
Object.values(myObject)
La réponse acceptée présente deux inconvénients:
Array.prototype.reduce
, car réduire signifie changer la structure d'un type composite, ce qui ne se produit pas dans ce cas.Une approche fonctionnelle ES6 / ES2015
Veuillez noter que toutes les fonctions sont définies sous forme curry.
o
est réaffecté. Puisque Javascript transmet les valeurs de référence par partage , une copie superficielle deo
est générée. Nous pouvons maintenant muter à l'o
intérieuromap
sans mutero
dans la portée parent.map
la valeur de retour est ignorée, carmap
effectue une mutation deo
. Étant donné que cet effet secondaire reste à l'intérieuromap
et n'est pas visible dans la portée parent, il est totalement acceptable.Ce n'est pas la solution la plus rapide, mais une solution déclarative et réutilisable. Voici la même implémentation qu'une ligne, succincte mais moins lisible:
Addendum - pourquoi les objets ne sont-ils pas itérables par défaut?
ES2015 a spécifié l'itérateur et les protocoles itérables. Mais les objets ne sont toujours pas itérables et donc non mappables. La raison en est le mélange des données et du niveau du programme .
la source
Array.prototype.reduce
plus. Tout ce que je veux illustrer ici, c'est que la réponse acceptée est en quelque sorte «des abus»Array.prototype.reduce
et comment une cartographie purement fonctionnelle pourrait être mise en œuvre. Si vous n'êtes pas intéressé par la programmation fonctionnelle, ignorez simplement ma réponse.fold
est plus générique qu'unmap
(foncteur). Cependant, c'était ma connaissance de la mi-2016. C'est une demi-éternité: DJavaScript vient de recevoir la nouvelle
Object.fromEntries
méthode.Exemple
Explication
Le code ci-dessus convertit l'objet en un tableau imbriqué (
[[<key>,<value>], ...]
) sur lequel vous pouvez mapper.Object.fromEntries
reconvertit le tableau en objet.La chose intéressante à propos de ce modèle, c'est que vous pouvez maintenant facilement prendre en compte les clés d'objet lors du mappage.
Documentation
Object.fromEntries()
Object.entries()
Prise en charge du navigateur
Object.fromEntries
n'est actuellement pris en charge que par ces navigateurs / moteurs , néanmoins il existe des polyfills disponibles (par exemple @ babel / polyfill ).la source
Object.fromEntries
c'est l'opposé deObject.entries
.Object.entries
convertit un objet en une liste de paires clé-valeur.Object.fromEntries
convertit une liste de paires clé-valeur en un objet.Version minimale (es6):
la source
Object.entries(obj).reduce((a, [k, v]) => [a[k] = v * v, a], {})
, crochets angulaires au lieu de parenthèses.Object.entries(obj).reduce((a, [k, v]) => {a[k] = v * v; return a}, {})
Object.entries().reduce
est la meilleure solution , je pense avec ES6 + .Would obtenir plus upvotes si elle a utilisé unereturn
déclaration dans le réducteur plutôt queimplicit return
et l'comma
opérateur - qui est propre mais difficile à lire à mon humble avisPour des performances maximales.
Si votre objet ne change pas souvent mais doit être itéré souvent, je suggère d'utiliser une carte native comme cache.
Object.entries fonctionne déjà dans Chrome, Edge, Firefox et beta Opera, c'est donc une fonctionnalité évolutive. C'est de ES7 donc polyfill il https://github.com/es-shims/Object.entries pour IE où cela ne fonctionne pas.
la source
const fn = v => v * 2; const newObj = Object.entries(myObject).reduce((acc, [k,v]) => Object.assign({}, acc, {[k]: fn(v)}), {});
vous pouvez utiliser la
map
méthode etforEach
sur les tableaux mais si vous souhaitez l'utiliser,Object
vous pouvez l'utiliser avec une torsion comme ci-dessous:Utilisation de Javascript (ES6)
Utilisation de jQuery
Ou vous pouvez également utiliser d'autres boucles comme
$.each
méthode comme dans l'exemple ci-dessous:la source
$
est jquery?Le
map function
n'existe pas sur leObject.prototype
mais vous pouvez l'imiter comme çala source
typeof callback === 'function'
absolument redondants. 1)map
n'a pas de sens sans rappel 2) sicallback
n'est pas une fonction, votremap
implémentation s'exécute simplement sans signification pour la boucle. En outre,Object.prototype.hasOwnProperty.call( obj, key )
c'est un peu exagéré.Je suis tombé sur cela en tant que premier élément d'une recherche Google essayant d'apprendre à le faire, et j'ai pensé partager avec d'autres personnes qui trouveraient récemment la solution que j'ai trouvée, qui utilise le package npm immuable.
Je pense qu'il est intéressant de partager car immutable utilise la situation EXACT de l'OP dans sa propre documentation - ce qui suit n'est pas mon propre code mais tiré de la documentation immuable-js actuelle:
Non pas que Seq ait d'autres propriétés ("Seq décrit une opération paresseuse, leur permettant de chaîner efficacement l'utilisation de toutes les méthodes de collecte d'ordre supérieur (telles que la carte et le filtre) en ne créant pas de collections intermédiaires") et que certaines autres données immuable-js les structures pourraient également faire le travail assez efficacement.
Quiconque utilise cette méthode devra bien sûr
npm install immutable
et voudra peut-être lire les documents:https://facebook.github.io/immutable-js/
la source
EDIT: La manière canonique d'utiliser les nouvelles fonctionnalités JavaScript est -
Où
o
est un objet etf
est votre fonction de mappage. Ou nous pourrions dire, étant donné une fonction dea -> b
, et un objet avec des valeurs de typea
, produire un objet avec des valeurs de typeb
. En tant que signature de pseudo-type -La réponse originale a été écrite pour démontrer un puissant combinateur,
mapReduce
qui nous permet de penser notre transformation d'une manière différentem
, la fonction de mappage - vous donne une chance de transformer l'élément entrant avant…r
, la fonction de réduction - cette fonction combine l'accumulateur avec le résultat de l'élément mappéIntuitivement,
mapReduce
crée un nouveau réducteur auquel nous pouvons nous connecter directementArray.prototype.reduce
. Mais plus important encore, nous pouvons implémenteromap
clairement notre implémentation de foncteur d'objet en utilisant le monoïde objet,Object.assign
et{}
.Remarquez que la seule partie du programme que nous avons dû écrire est l'implémentation de la cartographie elle-même -
Qui dit, étant donné un objet connu
o
et une clék
, construire un objet et dont la propriété calculéek
est le résultat de l'appelf
à la valeur de la clé,o[k]
.Nous obtenons un aperçu du
mapReduce
potentiel de séquençage de si nous faisons d'abord un résuméoreduce
Tout fonctionne de la même manière, mais
omap
peut maintenant être défini à un niveau supérieur. Bien sûr, le nouveauObject.entries
rend cela ridicule, mais l'exercice est toujours important pour l'apprenant.Vous ne verrez pas tout le potentiel d'
mapReduce
ici, mais je partage cette réponse car il est intéressant de voir combien d'endroits peuvent être appliqués. Si vous êtes intéressé par la façon dont il est dérivé et par d'autres moyens qui pourraient être utiles, veuillez consulter cette réponse .la source
Map
etMap.entries
, OK: D. Je suis fatigué d'abuser des objets simples comme types de données cartographiques.Map
devrait être utilisé où / quand c'est possible, mais cela ne remplace pas totalement la nécessité d'utiliser ces procédures sur des objets JS simples tho: DBasé sur la réponse @Amberlamps, voici une fonction utilitaire (en tant que commentaire, elle avait l'air moche)
et l'utilisation est:
la source
la source
enumerable
par défautfalse
Ma réponse est largement basée sur la réponse la mieux notée ici et j'espère que tout le monde comprend (ayez la même explication sur mon GitHub aussi). C'est pourquoi son implémentation avec la carte fonctionne:
Le but de la fonction est de prendre un objet et de modifier le contenu d'origine de l'objet en utilisant une méthode disponible pour tous les objets (objets et tableaux de la même manière) sans retourner de tableau. Presque tout dans JS est un objet, et pour cette raison, des éléments plus bas dans le pipeline d'héritage peuvent potentiellement techniquement utiliser ceux disponibles pour ceux qui sont en amont (et l'inverse, il apparaît).
La raison pour laquelle cela fonctionne est due aux fonctions .map renvoyant un tableau EXIGEANT que vous fournissiez un RETOUR explicite ou implicite d'un tableau au lieu de simplement modifier un objet existant. Vous trompez essentiellement le programme en pensant que l'objet est un tableau en utilisant Object.keys qui vous permettra d'utiliser la fonction de carte avec son action sur les valeurs auxquelles les clés individuelles sont associées (j'ai en fait renvoyé des tableaux par erreur mais je l'ai corrigé). Tant qu'il n'y a pas de retour dans le sens normal, il n'y aura pas de tableau créé avec l'objet d'origine toujours intact et modifié comme programmé.
Ce programme particulier prend un objet appelé images et prend les valeurs de ses clés et ajoute des balises url à utiliser dans une autre fonction. L'original est le suivant:
... et modifié est ceci:
La structure d'origine de l'objet est laissée intacte, ce qui permet un accès normal à la propriété tant qu'il n'y a pas de retour. Ne le faites pas renvoyer un tableau comme d'habitude et tout ira bien. Le but est de RÉASSIGNER les valeurs originales (images [clé]) à ce qui est voulu et pas à autre chose. Pour autant que je sache, afin d'empêcher la sortie du tableau, il DOIT y avoir RÉASSIGNATION des images [clé] et aucune demande implicite ou explicite de renvoyer un tableau (l'affectation des variables fait cela et me faisait des allers-retours).
ÉDITER:
Je vais aborder son autre méthode concernant la création de nouveaux objets pour éviter de modifier l'objet d'origine (et une réaffectation semble toujours nécessaire pour éviter de créer accidentellement un tableau en sortie). Ces fonctions utilisent la syntaxe des flèches et le sont si vous voulez simplement créer un nouvel objet pour une utilisation future.
Le fonctionnement de ces fonctions est le suivant:
mapFn prend la fonction à ajouter plus tard (dans ce cas (valeur) => valeur) et renvoie simplement tout ce qui y est stocké comme valeur pour cette clé (ou multiplié par deux si vous modifiez la valeur de retour comme il l'a fait) dans mapFn ( obj) [clé],
puis redéfinit la valeur d'origine associée à la clé dans result [key] = mapFn (obj) [key]
et renvoie l'opération effectuée sur le résultat (l'accumulateur situé dans les parenthèses initiée à la fin de la fonction .reduce).
Tout cela est effectué sur l'objet choisi et TOUJOURS IL NE PEUT PAS y avoir de demande implicite pour un tableau retourné et ne fonctionne que lors de la réaffectation de valeurs pour autant que je sache. Cela nécessite une certaine gymnastique mentale, mais réduit les lignes de code nécessaires, comme on peut le voir ci-dessus. La sortie est exactement la même que celle illustrée ci-dessous:
Gardez à l'esprit que cela a fonctionné avec NON-NUMBERS. Vous POUVEZ dupliquer N'IMPORTE QUEL objet en RETOURNANT SIMPLEMENT LA VALEUR dans la fonction mapFN.
la source
La première fonction répond à la question. Il crée une carte.
La deuxième fonction ne crée pas de carte. Au lieu de cela, il parcourt les propriétés de l'objet existant à l'aide de
hasOwnProperty()
. Cette alternative de carte peut être une meilleure solution dans certaines situations.la source
Si vous êtes intéressé à
map
ping non seulement des valeurs mais aussi des clés, j'ai écritObject.map(valueMapper, keyMapper)
, cela se comporte de cette façon:la source
npm install @mattisg/object.map
.J'avais besoin d'une version qui permettait également de modifier les clés (basée sur les réponses @Amberlamps et @yonatanmn);
factObject =
Edit: légère modification à passer dans l'objet de départ {}. Permet qu'il soit [] (si les clés sont des entiers)
la source
Je voulais spécifiquement utiliser la même fonction que j'utilisais pour les tableaux pour un seul objet, et je voulais rester simple. Cela a fonctionné pour moi:
la source
var mapped = myMapFunction(item)
Pour répondre de plus près à ce que le PO a précisément demandé, le PO veut un objet:
d'avoir une méthode de carte
myObject.map
,La meilleure réponse (mesurée en termes de " proche de ce qui est demandé " + "aucun ES {5,6,7} requis inutilement") serait:
Le code ci-dessus évite d'utiliser intentionnellement les fonctionnalités de langage, uniquement disponible dans les éditions récentes d'ECMAScript. Avec le code ci-dessus, le problème peut être résolu lke ceci:
En plus d'être mal vu par certains, ce serait une possibilité d'insérer la solution dans la chaîne prototype comme celle-ci.
Quelque chose qui, lorsqu'il est effectué avec une surveillance attentive, ne devrait avoir aucun effet néfaste et ne pas avoir d'incidence sur la
map
méthode d'autres objets (c'est-à-dire les tableauxmap
).la source
Tout d'abord, convertissez votre HTMLCollection à l'aide d'Object.entries (collection). Ensuite, c'est un itérable, vous pouvez maintenant utiliser la méthode .map dessus.
référence https://medium.com/@js_tut/calling-javascript-code-on-multiple-div-elements-without-the-id-attribute-97ff6a50f31
la source
Définissez une fonction mapEntries.
mapEntries prend une fonction de rappel qui est appelée sur chaque entrée de l'objet avec la valeur des paramètres, la clé et l'objet. Il doit renvoyer une nouvelle valeur.
mapEntries doit renvoyer un nouvel objet avec les nouvelles valeurs renvoyées par le rappel.
Edit: une version précédente ne spécifiait pas que ce n'était pas une propriété énumérable
la source
Hey a écrit une petite fonction de mappeur qui pourrait aider.
la source
Une autre approche consiste à utiliser une fonction json stringify personnalisée qui peut également fonctionner sur des objets profonds. Cela peut être utile si vous avez l'intention de le publier sur le serveur en tant que json
la source
Je gère uniquement les chaînes pour réduire les exemptions:
la source
Mappeur d'objets dans TypeScript
J'aime les exemples qui utilisent
Object.fromEntries
comme celui-ci , mais quand même, ils ne sont pas très faciles à utiliser. Les réponses qui utilisentObject.keys
puis recherchent lekey
font en fait plusieurs recherches qui peuvent ne pas être nécessaires.Je souhaitais qu'il y ait une
Object.map
fonction, mais nous pouvons créer la nôtre et l'appelerobjectMap
avec la possibilité de modifier les deuxkey
etvalue
:Utilisation (JavaScript):
Code (TypeScript):
Si vous n'utilisez pas TypeScript, copiez le code ci-dessus dans TypeScript Playground pour obtenir le code JavaScript.
En outre, la raison pour laquelle je l' ai mis
keySelector
aprèsvalSelector
dans la liste des paramètres, c'est parce que c'est facultatif.* Un certain mérite revient à la réponse d'Alexander-Mills .
la source
Cette fonction parcourt récursivement l'objet et les tableaux d'objets. Les attributs peuvent être supprimés s'ils sont renvoyés non définis
la source