Itérer sur les attributs d'objet et les modifier

Soulignement.js fournit _.each et _.map sur les collections, ce qui est agréable, mais j'ai besoin d'itérer sur tous les attributs de mon objet. J'ai besoin de modifier les valeurs et préserver les touches. Par exemple, j'ai quelque chose comme: {a:1, b:2, c:3} et j'ai besoin d'effectuer une opération qui change la valeur mais garde les clés. Disons, je vais calculer des carrés, je devrais obtenir {a:1, b:4, c:9}. La question Est: Comment faire cela en utilisant underscore (pas intéressé par JavaScript vanille)? J'adorerais une méthode comme:

var a = {a:1, b:2, c:3}
_.magic(a, function(item){ return item*item; });

En outre, ce serait génial si cela était possible de l'enchaîner, puisque je fais une carte, videz le résultat pour effectuer chacun, puis utilisez à nouveau une carte (parce que j'en ai besoin).

21
demandé sur GG. 2014-09-24 13:51:06

4 réponses

J'ai regardé un peu plus dans certains de mes extraits pour voir s'il y avait une option pour muter l'objet original, mais je n'ai rien trouvé d'intéressant, donc j'irais avec Ceci :\

var original = {a:1, b:2, c:3};
var squaredValues = _.object(_.map(original, function (value, key) {
    return [key, value * value];
}));

J'espère qu'il y a une solution plus élégante cependant.

17
répondu Javier92 2017-05-23 12:10:36

_.mapObject (ajouté dans la version 1.8) est exactement ce que vous cherchez.


Pour les versions précédentes, peut muter l'objet d'origine en utilisant le troisième argument du rappel _.each.

_.each({a:1, b:2, c:3}, function(value, key, obj) { obj[key] = value * value; });

L'utilisation de _.reduce avec un mémo initial peut également créer un nouvel objet.

_.reduce({a:1, b:2, c:3}, function(memo, value, key) {
    memo[key] = value * value;
    return memo;
}, {});

Je préférerais l'approche _.reduce. Un simple mixin le fera se comporter exactement comme _.map.

_.mixin({
    magic: function(obj, iterator, context) {
        return _.reduce(obj, function(memo, value, key) {
            memo[key] = iterator.call(context, value, key, obj);
            return memo;
        }, {});
    }
});
37
répondu Justin 2015-07-06 19:42:09

Comme Justin a dit _.mapObject peut-être ce que vous cherchiez. Mais cela crée un nouvel objet (étendant {}) qui pourrait ne pas être ce que vous voulez (par exemple si ce n'est pas un objet simple comme new THREE.Vector3()), Ici, il n'est pas bon de remplacer l'objet original par quelque chose de différent.

Pour ce cas (modification de valeurs dans, l'objet donné) juste utiliser _.chaque avec le troisième paramètre de votre fonction iteratee:

_.each(complexObject, function(value, key, obj) {
  obj[key] = value * value;
}); 
4
répondu estani 2016-09-11 09:17:46

Un grand merci à Javier92 qui m'a montré la bonne solution.

Quoi qu'il en soit, je n'aime pas utiliser une méthode de soulignement qui utilise deux autres méthodes de soulignement (ce n'est pas très lisible), donc je suis venu avec une fonction wrapper simple qui est mélangée dans underscore:

// mixin to make our new function available via _
_.mixin({
    updateAttributes: function(object, iteratee) {
        return _.object(_.map(object, function (value, key) {
            return [key, iteratee(value)];
        }));
    }
});

Utilisez-le quelque part dans votre code:

_.updateAttributes({a:1, b:2, c:3}, function(item){ return item*item; })
// Object {a: 1, b: 4, c: 9}

Ne pouvait pas penser à une fonction d'un mot (il y a probablement quelque chose de mieux que updateAttributes).

1
répondu ducin 2014-09-24 10:06:44