web-dev-qa-db-fra.com

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

Underscore.js fournit _.each et _.map sur les collections, ce qui est bien, mais je dois parcourir tous les attributs de mon objet. Je dois modifier les valeurs et conserver les clés. Par exemple. J'ai quelque chose comme: {a:1, b:2, c:3} et je dois effectuer une opération qui modifie la valeur mais conserve les clés. Disons que je vais calculer des carrés, je devrais obtenir {a:1, b:4, c:9}. La question est: comment faire cela en utilisant le soulignement (pas intéressé par le javascript Vanilla)? J'adorerais une méthode comme:

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

De plus, ce serait formidable si cela était possible de l'enchaîner, car je fais une carte, vider le résultat pour effectuer chacun, puis utiliser à nouveau une carte (car j'en ai besoin).

21
ducin

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

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

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

17
Javier92

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


Pour les versions précédentes, peut muter l'objet d'origine à l'aide du troisième argument du _.each rappeler.

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

En utilisant _.reduce avec un mémo initial peut également créer un tout nouvel objet.

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

Je préfère le _.reduce approche. 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
Justin

Comme Justin l'a dit _. MapObject pourrait ê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 simple objet comme new THREE.Vector3()), Ici, il ne sert à rien de remplacer l'objet d'origine par quelque chose de différent.

Dans ce cas (en modifiant les valeurs en place in l'objet donné) utilisez simplement _. Each avec le troisième paramètre de votre fonction itérative:

_.each(complexObject, function(value, key, obj) {
  obj[key] = value * value;
}); 
4
estani

Un grand merci à Javier92 qui m'a indiqué 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 beaucoup lisible), alors j'ai trouvé une fonction d'encapsuleur simple qui est mélangée dans un trait de soulignement:

// 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 (probablement il y a quelque chose de mieux que updateAttributes).

1
ducin