Lodash: Construire un seul objet à partir de nombreux – Propriétés de fusion / remplacement

Remarque: J'ai déposé cette question sous lodash, car je suis sûr que cela peut m'aider à résoudre ce problème très bien, mais je n'ai pas mis le doigt dessus tout à l'heure

J'ai un objet décrivant différents rôles d'utilisateur et leurs autorisations;

J'aurai quelque chose comme 10-15 rôles définis "comme ceci" ( cela ne reflète pas le code de l'application mais le problème lui-même ):

var role1 = { views: { v1: {access: true}, v2: {access: false}, v#: {access: false} } } var role2 = { views: { v1: {access: false}, v2: {access: true}, v3: {access: true}, } } 

L'utilisateur connecté aura plusieurs rôles; Dans cet exemple, il pourrait être ['role1', 'role2'] , et de ce fait, je dois construire un objet d' permissions unique qui sera une combinaison de tous les accessoires définis dans tous les rôles d'utilisateur.

Il est fondamentalement basé sur la liste blanche, où toutes les propriétés "vraies" doivent remplacer tout ce qui a été défini comme faux. Ainsi, le résultat attendu devrait être:

 permissions = { views: { v1: {access: true}, v2: {access: true}, v2: {access: true} } } 

Je ne suis pas trop sûr de savoir comment s'attaquer à celui-là sans compter sur des boucles imbriquées fou

Voici un point de départ dans JSBin: http://jsbin.com/usaQejOJ/1/edit?js,console

Merci de votre aide!

Lodash dispose de quelques méthodes qui aideront à résoudre ce problème avec élégance.

Tout d'abord, la méthode de merge . Il prend plusieurs objets source et fusionne récursivement leurs propriétés ensemble dans un objet de destination. Si deux objets ont le même nom de propriété, la dernière valeur remplacera le premier.

C'est presque ce que nous voulons; Il fusionnera vos objets de rôle ensemble en un seul objet. Ce que nous ne voulons pas, c'est que le comportement de substitution; Nous voulons que true valeurs true remplacent toujours les false . Heureusement, vous pouvez passer une fonction de fusion personnalisée, et la merge de lodash l'utilisera pour calculer la valeur fusionnée lorsque deux objets ont la même clé.

Nous écrirons une fonction personnalisée sur TOUT OR vos éléments ensemble (au lieu de permettre aux valeurs false ultérieures de remplacer les true s.), De sorte que si l'une ou l'autre valeur est true , la valeur fusionnée résultante sera true .

Parce que nos objets sont imbriqués, nous devrons nous assurer que notre fonction de fusion personnalisée ne fait que cette OR lorsqu'elle compare des valeurs booléennes. Lors de la comparaison d'objets, nous voulons faire une fusion normale de leurs propriétés (en utilisant à nouveau notre fonction personnalisée pour faire la fusion). Cela ressemble à ceci:

 function do_merge(roles) { // Custom merge function ORs together non-object values, recursively // calls itself on Objects. var merger = function (a, b) { if (_.isObject(a)) { return _.merge({}, a, b, merger); } else { return a || b; } }; // Allow roles to be passed to _.merge as an array of arbitrary length var args = _.flatten([{}, roles, merger]); return _.merge.apply(_, args); } do_merge([role1, role2, role3]); 

Lodash aide d'une autre manière: vous pouvez remarquer des documents que _.merge n'accepte pas un éventail d'objets pour fusionner ensemble; Vous devez les transmettre comme arguments. Dans notre cas, cependant, un tableau serait terriblement pratique.

Pour contourner cela, nous utiliserons la méthode d' apply de JavaScript, qui vous permet d'invoquer une méthode en passant ses arguments en tant que tableau, et la méthode d' flatten pratique de Lodash, qui prend un tableau qui pourrait contenir des tableaux imbriqués – comme [1, [2, 3], [4, 5]] – et l'aplatit en [1, 2, 3, 4, 5] .

Nous rassemblerons donc tous les arguments dont nous avons besoin dans une matrice plate, puis les apply pour merge !

Si vos objets sont imbriqués très profondément, vous risquez de déborder la merger appel de la pile de façon récursive comme celle-ci, mais pour vos objets, cela devrait fonctionner très bien.