web-dev-qa-db-fra.com

Un booléen JS ayant des propriétés personnalisées est-il une mauvaise pratique?

Dans JS, vous pouvez renvoyer un booléen ayant des propriétés personnalisées. Par exemple. lorsque Modernizr teste la prise en charge de la vidéo, il renvoie true ou false mais le booléen renvoyé (Bool est un objet de première classe dans JS) possède des propriétés spécifiant les formats pris en charge. Au début, cela m'a un peu surpris mais ensuite j'ai commencé à aimer l'idée et j'ai commencé à me demander pourquoi elle semble être utilisée avec parcimonie?

Cela ressemble à une manière élégante de gérer tous ces scénarios où vous voulez essentiellement savoir si quelque chose est vrai ou faux mais vous pouvez être intéressé par des informations supplémentaires que vous pouvez définir sans définir un objet de retour personnalisé ou en utilisant une fonction de rappel préparée pour accepter plus de paramètres. De cette façon, vous conservez une signature de fonction très universelle sans compromettre la capacité de retour de données plus complexes.

Il y a 3 arguments contre cela que je peux imaginer:

  1. C'est un peu rare/inattendu quand il vaut probablement mieux que n'importe quelle interface soit claire et pas compliquée.
  2. Cela peut être un argument de paille, mais avec un peu un cas Edge, je peux imaginer qu'il se retourne silencieusement dans certains optimiseurs JS, uglifier, VM ou après un changement mineur de spécification du langage de nettoyage) etc.
  3. Il existe une meilleure façon - concise, claire et commune - de faire exactement la même chose.

Ma question est donc la suivante: y a-t-il de bonnes raisons d'éviter d'utiliser des booléens avec des propriétés supplémentaires? Est-ce un truc ou un régal?


Avertissement de torsion du tracé.

Ci-dessus est la question d'origine en pleine gloire. Comme Matthew Crumley et senevoldsen l'ont tous deux souligné, cela est basé sur une prémisse fausse (fausse?). Dans la tradition de JS, ce que Modernizr fait est un tour de langage et un sale. Cela revient à JS ayant un bool primitif qui, s'il est défini sur false, restera faux même après avoir essayé d'ajouter des accessoires (qui échoue silencieusement) et un objet booléen qui peut avoir des accessoires personnalisés, mais être un objet est toujours véridique. Modernizr renvoie soit un booléen faux, soit un objet booléen véridique.

Ma question d'origine supposait que l'astuce fonctionne différemment et que les réponses les plus populaires concernent donc l'aspect (parfaitement valide) des normes de codage. Cependant, je trouve les réponses démystifiant l'astuce la plus utile (et aussi les arguments ultimes contre l'utilisation de la méthode), donc j'accepte l'une d'entre elles. Merci à tous les participants!

40
konrad

En plus des principes généraux de conception, comme la responsabilité unique et la moindre surprise, il y a une raison spécifique à JavaScript que ce n'est pas une bonne idée: il y a une énorme différence entre un boolean et Boolean en JavaScript cela l'empêche de fonctionner dans le cas général.

boolean est un type primitif, pas un objet, et ne peut pas avoir de propriétés personnalisées. Des expressions comme true.toString() fonctionnent parce que dans les coulisses, cela se transforme en (new Boolean(true)).toString().

Boolean (avec un B majuscule) est un objet, mais a très peu de bonnes utilisations, et étant utilisé comme boolean n'en fait certainement pas partie. La raison en est que chaque Boolean est "vrai", quelle que soit sa valeur, car tous les objets sont convertis en true dans un contexte booléen. Par exemple, essayez ceci:

var answer = new Boolean(false);
if (answer) {
  console.log("That was unexpected.");
}

Donc, en général, il n'y a aucun moyen d'ajouter des propriétés à un booléen en JavaScript qui permet toujours de se comporter de manière logique. Modernizr peut s'en tirer car les seules ajoutent des propriétés aux "vraies" valeurs, qui fonctionnent comme vous vous en doutez (c'est-à-dire qu'elles fonctionnent dans les instructions if). Si la vidéo n'est pas prise en charge du tout, Modernizr.video sera un boolean réel (avec la valeur false) et ne pourra pas avoir de propriétés ajoutées.

37
Matthew Crumley

Félicitations, vous avez découvert des objets. La raison de ne pas le faire est appelée principe du moindre étonnement . Être surpris par un design n'est pas une bonne chose.

Il n'y a rien de mal à regrouper ces informations, mais pourquoi voudriez-vous les cacher dans un Bool? Mettez-le dans quelque chose que vous attendez d'avoir toutes ces informations. Bool inclus.

58
candied_orange

L'argument principal contre lequel je m'oppose est le principe de responsabilité unique, un booléen ne devrait dire que si quelque chose est true ou false, pas pourquoi ni comment ou tout autre chose. J'ai la ferme conviction et la pratique que d'autres objets devraient être utilisés pour communiquer cette information ou toute autre information.

16
J. Pichardo

Puisque toute la raison pour laquelle on l'appelle une valeur booléenne est le fait qu'elle soit vraie ou fausse, je n'aime pas l'idée, car vous sapez à peu près tout son objectif de wikipedia

En informatique, le type de données booléen est un type de données, ayant deux valeurs (généralement notées vrai et faux), destinées à représenter les valeurs de vérité de la logique et de l'algèbre booléenne .

(mon audace)

10
user232573

Ce n'est pas parce que vous le pouvez que vous le devriez, dans JS, vous pouvez à peu près attacher des propriétés à n'importe quel objet (booléens inclus)

En quoi est-ce une mauvaise chose?

D'une part, vous pouvez attacher plus de données non pertinentes à un booléen (selon votre exemple), ce à quoi un autre développeur ne s'attendra pas car pourquoi devrait-il être là?! bools sont juste pour vrai et faux.

Un contre-point pour cela est d'attacher quelques propriétés utiles pertinentes qui peuvent vous aider à gérer la valeur booléenne ( Java le fait ).

Par exemple, vous pouvez attacher une fonction qui convertit la valeur booléenne en chaîne, un indicateur dirty qui est devenu vrai si la valeur a été modifiée, des observateurs et des rappels d'événements qui peuvent se déclencher lorsque la valeur est modifiée, etc.

mais le Boolean retourné (Bool est un objet de première classe dans JS) a des propriétés spécifiant quels formats sont pris en charge

Cela ressemble à quelque chose qui ne devrait pas être stocké dans un booléen, mais plutôt à l'aide d'un ensemble de booléens ou d'un ensemble de propriétés avec des booléens à l'intérieur. Je pense qu'une meilleure approche serait de retourner un objet avec tous les formats et détails de support.

{
    isSomethingSupported: true,
    isSomethingElseSupported: false,
    ....
}
2
svarog

Vous ne pouvez pas faire de booléens avec des propriétés personnalisées en JavaScript. Les échecs suivants (au moins dans FF):

    var x = false;
    x.foo = "bar";
    console.log(x.foo);

Vous pouvez utiliser ou hériter de Boolean, mais comme le dit Matthew Crumley, cela donne des résultats différents. Boolean est de type Object. Lorsque JS a besoin de la valeur booléenne d'une expression, il convertit à l'aide de la fonction de spécification ToBoolean, qui stipule que pour Objects, le résultat est toujours true. Ainsi, la valeur new Boolean(false) est évaluée à true! Vous pouvez le vérifier dans cet exemple: https://jsfiddle.net/md7abx5z/3/ .

La seule raison pour laquelle cela fonctionne pour Modernizr est accessoire. Ils ne créent un objet Boolean que lorsque la condition est vraie. Quand ils évaluent faux, ils retournent simplement false ordinaire. Cela fonctionne donc car ils ne renvoient que des objets Boolean quand le résultat est vrai de toute façon, et jamais quand il est faux.

1
senevoldsen

Je comprends que le contexte a changé, mais je voudrais répondre à la question initiale que j'ai lue comme utilisant JS comme exemple, mais pas uniquement JS.

L'ajout de propriétés à un booléen ne serait pas un problème SI les propriétés avaient quelque chose à voir avec le vrai/faux, pas avec la variable contenant la valeur. Par exemple, l'ajout d'une méthode toYesNoString serait bien, l'ajout d'un numberOfChildren à une valeur hasChildren ne l'est pas, pas plus que questionsMissed studentPassed. Il n'y a pas grand-chose que vous pourriez ajouter à un booléen, à part diverses représentations de chaînes, la seule propriété à laquelle je pense qui aurait du sens est originalExpression. Mais y ajouter n'est pas nécessairement une mauvaise idée en théorie.

1
jmoreno

Dans l'exemple donné, ne pourriez-vous pas renvoyer simplement un tableau de tous les formats vidéo pris en charge?

  • Un tableau vide signifie "pas de formats vidéo pris en charge", ce qui signifie dans l'ordre "pas vidéo pris en charge ".
  • Sinon, si un format vidéo est pris en charge, alors évidemment vidéo en général est pris en charge.

Je dirais au moins qu'utiliser array est un peu moins surprenant que d'avoir des "booléens personnalisés".

En Javascript, un tableau vide est même considéré faux , tandis qu'un tableau non vide est véridique , donc avec un peu de chance, vous pouvez simplement passer aux tableaux et tout fonctionnerait comme avant  éditer Non, idiot de penser que je pourrais me souvenir de la véracité des objets en JavaScript: P

0
daniero

Si je regarde le code, il ne s'agit pas vraiment de donner des propriétés personnalisées booléennes mais d'une méthode ayant des méthodes de retour avec des signatures différentes.

S'il est faux, vous obtenez un faux primitif et s'il est vrai, il renvoie un objet qui, par définition, est interprété comme vrai en javascript.

Donc, à mon avis, votre question ne devrait pas être de savoir si c'est une bonne idée de donner des propriétés personnalisées booléennes, mais si c'est une bonne idée d'avoir des méthodes avec plusieurs signatures de retour.

0
Pieter B