30 votes

Validation JavaScript de plusieurs booléens

Je veux valider un objet qui possède trois propriétés booléennes, dont une, et une seule, doit être vraie. Quelle est la meilleure façon de vérifier cela ?

J'ai trouvé ça :

var t1 = obj.isFirst  ? 1 : 0,
    t2 = obj.isSecond ? 1 : 0,
    t3 = obj.isThird  ? 1 : 0;

var valid = (t1 + t2 + t3) === 1;

Cela fonctionne bien, mais cela ressemble un peu à une solution d'amateur :-)

Y a-t-il une meilleure façon de procéder ? En utilisant XOR (^) par exemple ?

5 votes

obj.isFirst + obj.isSecond + obj.isThird === 1 en supposant qu'il est certain qu'il s'agit de booléens et non de quelque chose de différent. Vous pouvez ajouter une conversion explicite si vous le souhaitez (par ex. Number(obj.isFirst) ), mais javascript convertit aussi implicitement.

0 votes

En rapport : Pourquoi n'y a-t-il pas de xor logique en JavaScript ? dont les réponses comprennent des alternatives.

11 votes

Ressemble un peu à une solution de bricoleur, je peux vous assurer que les pros écrire un code qui ressemble exactement à ça. Arrêtez de vous préoccuper de l'apparence de votre code, personne ne le regardera, assurez-vous que le compilateur peut le lire et qu'il fait ce qu'il doit faire.

19voto

mmm Points 17173

Vous pourriez filtrer les valeurs de l'objet et vérifier si la longueur est de 1.

let obj = {
    a: true,
    b: false,
    c: false
};
let oneTrue = Object.values(obj).filter(e => e === true).length === 1;
console.log(oneTrue);

Comme @deceze l'a commenté

Il devrait y avoir plus de propriétés dans l'objet : [obj.a, obj.b, obj.c].filter(Boolean)...


Notez que dans votre cas, il peut être judicieux d'ajouter une méthode à votre objet qui effectue la vérification pour vous.

let obj = {
    a: false,
    b: false,
    c: false,
    isValid() {
        return this.a + this.b + this.c === 1;
    }
};

console.log(obj.isValid());

4 votes

Il devrait y avoir plus de propriétés dans l'objet : [obj.a, obj.b, obj.c].filter(Boolean)

1 votes

Merci @deceze qui l'a ajouté comme citation à la réponse. Bon ajout

1 votes

Oui, mon objet a d'autres propriétés, mais je vois que cela fonctionnerait sans aucun doute autrement.

9voto

Faly Points 10850

Vous pouvez utiliser array.reduce :

var obj = {
    a: true,
    b: false,
    c: false
};
var res = Object.values(obj).reduce((m, o) => m + o) === 1;
console.log(res);

7voto

Rory O'Kane Points 4866

Utilisez :

obj.isFirst + obj.isSecond + obj.isThird === 1

En supposant qu'il est certain que les valeurs sont des booléens et pas quelque chose de différent. Vous pouvez ajouter une conversion explicite si vous le souhaitez, comme ceci :

Number(obj.isFirst) + Number(obj.isSecond) + Number(obj.isThird) === 1

Mais JavaScript effectue aussi implicitement cette conversion pour vous.

(Ceci est basé sur <a href="https://stackoverflow.com/users/6692606/asdfgerte">ASDFGerte </a>'s <a href="https://stackoverflow.com/questions/51383746/javascript-validation-of-multiple-booleans#comment89739442_51383746">commentaire </a>.)

2 votes

Si vous voulez vraiment ajouter des booléens, vous pouvez aussi les convertir avec !! . Et comme true est traitée comme une valeur numérique 1 y false comme 0 en Javascript, !!obj.isFirst + !!obj.isSecond + !!obj.isThird accomplit la même chose. Alternativement, + lance un nombre : +obj.isFirst + +obj.isSecond + +obj.isThird et maintenant j'ai mal à la tête.

0 votes

@Bucket utilisant !! sur un booléen ne sert à rien.

0 votes

Regardez ça : Number(1) + Number("true") + Number(true) vs Boolean(1) + Boolean("true") + Boolean(true)

4voto

Tibos Points 12774

Si l'on prend le problème dans l'autre sens, on dirait que vous essayez de modéliser quelque chose qui peut avoir 3 états possibles. Ne le représentez pas comme 3 booléens, représentez-le comme une variable avec 3 valeurs possibles :

const STATES = ['STATE_A', 'STATE_B', 'STATE_C'];
let value = 'STATE_A';

Si vous voulez utiliser l'un des booléens :

doSomethingDependingOnBooleanC(value === `STATE_C`);

Si vous voulez valider que value contient ce que vous attendez (un de vos 3 états possibles) :

const isValid = STATES.includes(value);
const isValidInOlderBrowsers = STATES.indexOf(value) !== -1;

2 votes

Pour aller plus loin, vous pouvez utiliser les propriétés des objets. const STATES = Object.freeze({STATE_A: 1, STATE_B: 2, STATE_C: 3}); let value = STATES.STATE_A; .

0 votes

@Yay295 C'est exactement la façon dont je le ferais, peut-être avec des symboles au lieu de chiffres pour les valeurs, mais je ne voulais pas compliquer la réponse avec la façon de définir un enum en JS. Ma réponse est "simplifiez votre modèle de données", pas "utilisez ce code qui fonctionne".

2voto

Bucket Points 5908

Vous pouvez faire cela en une ligne, mais ce n'est pas facile à lire. Mais si l'obscurcissement est votre objectif, continuez à lire.

Desde obj.isFirst , obj.isSecond y obj.isThird sont tous soit 0 o 1 vous pouvez utiliser l'opérateur XOR au niveau des bits. ^ entre eux :

(obj.isFirst ^ obj.isSecond ^ obj.isThird) ^ (obj.isFirst && obj.isSecond && obj.isThird)

Nous devons faire un XOR contre obj.isFirst && obj.isSecond && obj.isThird parce que obj.isFirst ^ obj.isSecond ^ obj.isThird évalue à true .

0 votes

Cela signifie donc que le PO doit coder en dur toutes ses propriétés, deux fois .

0 votes

Mais vous devez toujours définir t1 , t2 y t3 premier. Cela compte comme une partie de la réponse, ce qui fait quatre lignes au lieu de la seule ligne que vous montrez.

2 votes

Même si cela fonctionne, cela semble trop obscur et difficile à comprendre. Au minimum, il faut une ligne supplémentaire de commentaire pour expliquer ce qu'il fait, ce qui annule quelque peu son objectif.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X