Comment écrire une expression opérateur ternaire (aka if) sans se répéter

Par exemple, quelque chose comme ceci:

var value = someArray.indexOf(3) !== -1 ? someArray.indexOf(3) : 0 

Y a-t-il une meilleure façon d’écrire cela? Encore une fois, je ne cherche pas une réponse à la question exacte ci-dessus, juste un exemple de quand vous pourriez avoir des opérandes répétés dans des expressions d’opérateur ternaires …

Personnellement, je trouve que le meilleur moyen de le faire est toujours le bon vieux énoncé:

 var value = someArray.indexOf(3); if (value === -1) { value = 0; } 

Le code devrait être lisible, donc être succinct ne devrait pas signifier être concis, quel que soit le coût – pour cela, vous devriez vous reporter à https://codegolf.stackexchange.com/ – au lieu de cela, je vous recommande d’utiliser une seconde variable locale (avec un coût d’exécution minimal aussi, je note):

 var index = someArray.indexOf( 3 ); var value = index == -1 ? 0 : index; 

Mais si vous voulez vraiment réduire cette expression, parce que vous êtes un sadique cruel de vos collègues de travail ou de vos collaborateurs de projet, voici 4 approches que vous pouvez utiliser:

1: Variable temporaire dans une instruction var

Vous pouvez utiliser la capacité de l’instruction var pour définir (et affecter) un deuxième index variable temporaire séparé par des virgules:

 var index = someArray.indexOf(3), value = index !== -1 ? index: 0; 

2: Fonction anonyme à exécution automatique

Une autre option est une fonction anonyme à exécution automatique:

 // Traditional syntax: var value = function( x ) { return x !== -1 ? x : 0 }( someArray.indexOf(3) ); // ES6 syntax: var value = ( x => x !== -1 ? x : 0 )( someArray.indexOf(3) ); 

3: opérateur virgule

Il y a aussi le fameux “opérateur virgule” que JavaScript supporte, qui est également présent en C et C ++.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator

Vous pouvez utiliser l’opérateur de virgule lorsque vous souhaitez inclure plusieurs expressions dans un emplacement nécessitant une expression unique.

Vous pouvez l’utiliser pour introduire des effets secondaires, dans ce cas en réaffectant à la value :

 var value = ( value = someArray.indexOf(3), value !== -1 ? value : 0 ); 

Cela fonctionne parce que la var value est interprétée en premier (comme c’est une déclaration), puis la value plus à gauche, puis l’opérateur de la virgule, puis l’opérateur ternaire – tous les codes JavaScript légaux.

4: réassigner dans une sous-expression

Le commentateur @IllusiveBrian a souligné que l’utilisation de la virgule (dans l’exemple précédent) n’est pas nécessaire si l’affectation à value est utilisée comme sous-expression entre parenthèses:

 var value = ( ( value = someArray.indexOf(3) ) !== -1 ? value : 0 ); 

Notez que l’utilisation de négatifs dans les expressions logiques peut être plus difficile à suivre pour les humains. Ainsi, tous les exemples ci-dessus peuvent être simplifiés pour la lecture en changeant idx !== -1 ? x : y idx !== -1 ? x : y à idx == -1 ? y : x idx == -1 ? y : x :

 var value = ( ( value = someArray.indexOf(3) ) == -1 ? 0 : value ); 

Pour les nombres

Vous pouvez utiliser la fonction Math.max() .

 var value = Math.max( someArray.indexOf('y'), 0 ); 

Il gardera les limites du résultat de 0 jusqu’au premier résultat supérieur à 0 si tel est le cas. Et si le résultat de indexOf est -1 il retournera 0 comme étant supérieur à -1 .

Pour les valeurs booléennes et booléennes

Pour JS, il n’y a pas de règle générale AFAIK spécialement parce que les fausses valeurs sont évaluées.

Mais si quelque chose peut vous aider la plupart du temps, le ou l’opérateur ( || ):

 // Instead of var variable = this_one === true ? this_one : or_this_one; // you can use var variable = this_one || or_this_one; 

Vous devez faire très attention à cela, car dans votre premier exemple, indexOf peut retourner 0 et si vous évaluez 0 || -1 0 || -1 retournera -1 car 0 est une valeur falsifiée .

Pas vraiment, utilisez simplement une autre variable.

Votre exemple se généralise à quelque chose comme ça.

 var x = predicate(f()) ? f() : default; 

Vous testez une valeur calculée, puis vous affectez cette valeur à une variable si elle passe un certain prédicat. La manière d’éviter de recalculer la valeur calculée est évidente: utilisez une variable pour stocker le résultat.

 var computed = f(); var x = predicate(computed) ? computed : default; 

Je comprends ce que vous voulez dire – il semble y avoir un moyen de faire cela qui semble un peu plus propre. Mais je pense que c’est le meilleur moyen (idiomatique) de le faire. Si vous répétiez souvent ce motif dans votre code pour une raison quelconque, vous pourriez écrire une petite fonction d’aide:

 var setif = (value, predicate, default) => predicate(value) ? value : default; var x = setif(someArray.indexOf(3), x => x !== -1, 0) 

EDIT: Le voici, la proposition pour Nullary-coalescing maintenant en JavaScript!


Utiliser ||

const result = a ? a : 'fallback value';

est équivalent à

const result = a || 'fallback value';

Si la conversion en Boolean renvoie false , le result verra atsortingbuer 'fallback value' , sinon la valeur de a .


Soyez conscient du cas d’arête a === 0 , qui devient false et le result prendra (à tort) une 'fallback value' . Utilisez des astuces comme celle-ci à vos risques et périls.


PS Des langages tels que Swift ont un opérateur de coalescence nulle ( ?? ), qui sert un objective similaire. Par exemple, dans Swift, vous écrivez result = a ?? "fallback value" result = a ?? "fallback value" qui est assez proche du const result = a || 'fallback value'; de JavaScript const result = a || 'fallback value'; const result = a || 'fallback value';

Utilisez un refactoring de variable d’extraction :

 var index = someArray.indexOf(3); var value = index !== -1 ? index : 0 

C’est encore mieux avec const plutôt qu’avec var . Vous pouvez également faire une extraction supplémentaire:

 const index = someArray.indexOf(3); const condition = index !== -1; const value = condition ? index : 0; 

En pratique, utilisez des noms plus significatifs que l’ index , la condition et la value .

 const threesIndex = someArray.indexOf(3); const threeFound = threesIndex !== -1; const threesIndexOrZero = threeFound ? threesIndex : 0; 

Vous recherchez probablement un opérateur de coalescence. Heureusement, nous pouvons tirer parti du prototype Array pour en créer un:

 Array.prototype.coalesce = function() { for (var i = 0; i < this.length; i++) { if (this[i] != false && this[i] != null) return this[i]; } } [null, false, 0, 5, 'test'].coalesce(); // returns 5 

Cela pourrait être généralisé à votre cas, en ajoutant un paramètre à la fonction:

 Array.prototype.coalesce = function(valid) { if (typeof valid !== 'function') { valid = function(a) { return a != false && a != null; } } for (var i = 0; i < this.length; i++) { if (valid(this[i])) return this[i]; } } [null, false, 0, 5, 'test'].coalesce(); // still returns 5 [null, false, 0, 5, 'test'].coalesce(function(a){return a !== -1}); // returns null [null, false, 0, 5, 'test'].coalesce(function(a){return a != null}); //returns false 

Personnellement, je préfère deux variantes:

  1. Pure si, comme @slebetman suggéré

  2. Fonction séparée, qui remplace la valeur non valide par une valeur par défaut, comme dans cet exemple:

 function maskNegative(v, def) { return v >= 0 ? v : def; } Array.prototype.indexOfOrDefault = function(v, def) { return maskNegative(this.indexOf(v), def); } var someArray = [1, 2]; console.log(someArray.indexOfOrDefault(2, 0)); // index is 1 console.log(someArray.indexOfOrDefault(3, 0)); // default 0 returned console.log(someArray.indexOfOrDefault(3, 123)); // default 123 returned 

J’aime la réponse de @ slebetman. Le commentaire sous-jacent concerne l’inquiétude que la variable soit dans un “état intermédiaire”. Si cela vous préoccupe beaucoup, je suggère de l’encapsuler dans une fonction:

 function get_value(arr) { var value = arr.indexOf(3); if (value === -1) { value = 0; } return value; } 

Alors appelle juste

 var value = get_value( someArray ); 

Vous pouvez faire des fonctions plus génériques si vous en avez besoin dans d’autres endroits, mais ne surchargez pas si c’est un cas très spécifique.

Mais pour être honnête, je ferais comme @slebetman, sauf si je devais réutiliser à partir de plusieurs endroits.

Il y a deux façons de voir votre question: vous voulez soit réduire la longueur de la ligne, soit vous voulez spécifiquement éviter de répéter une variable dans un ternaire. Le premier est sortingvial (et de nombreux autres utilisateurs ont publié des exemples):

 var value = someArray.indexOf(3) !== -1 ? someArray.indexOf(3) : 0; 

peut être (et devrait être, étant donné les appels de fonction) raccourci comme cela:

 var value = someArray.indexOf(3); value = value !== -1 ? value : 0; 

Si vous cherchez une solution plus générique qui empêche la répétition d’une variable dans un ternaire, comme ceci:

 var value = conditionalTest(foo) ? foo : bar; 

foo apparaît seulement une fois. Jeter les solutions de la forme:

 var cad = foo; var value = conditionalTest(foo) ? cad : bar; 

comme techniquement correct mais manquant le point, alors vous n’avez pas de chance. Il y a des opérateurs, des fonctions et des méthodes qui possèdent la syntaxe laconique que vous recherchez, mais ces constructions, par définition, ne sont pas des opérateurs ternaires .

Exemples:

javascript, en utilisant || pour rendre le RHS lorsque le LHS est falsey :

 var value = foo || bar; // equivalent to !foo ? bar : foo 

Utilisez une fonction d’assistance:

 function translateValue(value, match, translated) { return value === match ? translated : value; } 

Maintenant, votre code est très lisible, et il n’y a pas de répétition.

 var value = translateValue(someArray.indexOf(3), -1, 0); 

La hiérarchie des problèmes de codage est la suivante:

  1. Correct (y compris les véritables problèmes de performance ou de SLA)
  2. Clair
  3. Concis
  4. Vite

Toutes les réponses sur la page semblent être correctes, mais je pense que ma version est la plus claire, ce qui est plus important que la concision. Si vous ne comptez pas la fonction d’assistance (car elle peut être réutilisée), elle est également la plus concise. La suggestion quelque peu similaire d’utiliser une fonction d’assistance utilise malheureusement un lambda qui, à mes yeux, ne fait que masquer ce qu’il fait. Une fonction plus simple avec un but qui ne prend pas un lambda, juste des valeurs, est pour moi beaucoup mieux.

PS Si vous aimez la syntaxe ES6:

 const translateValue = (value, match, translated) => value === match ? translated : value; let value = translateValue(someArray.indexOf(3), -1, 0); // or const 

Je pense que le || l’opérateur peut être adapté à indexOf :

 var value = ((someArray.indexOf(3) + 1) || 1) - 1; 

La valeur renvoyée est augmentée de 1, ce qui fait 0 de -1, ce qui correspond à falsey et est donc remplacé par le second 1. Ensuite, il est reculé.

Cependant, gardez à l’esprit que la lisibilité est supérieure à la répétition.

Ceci est une solution simple avec bit par bit et une valeur par défaut de -1 qui résulte plus tard à zéro.

 index = ~(~array.indexOf(3) || -1); 

Il fonctionne essentiellement avec un double bit NOT NOT, qui renvoie la valeur d’origine ou une valeur par défaut qui, après application au niveau du bit, renvoie zéro.

Regardons la table de la vérité:

  indexOf ~indexOf boolean default value result comment --------- --------- --------- --------- --------- --------- ------------------ -1 0 falsy -1 -1 0 take default value 0 -1 truthy -1 0 1 -2 truthy -2 1 2 -3 truthy -3 2 

Vous pouvez utiliser la réaffectation:

  • initialiser la variable à une valeur
  • utiliser la sérialisation de l’opérateur && pour la réaffectation, car si la première condition est fausse, la seconde expression ne sera pas évaluée

Ex.

 var value = someArray.indexOf(3); value == -1 && (value=0); 
 var someArray = [4,3,2,1]; var value = someArray.indexOf(1); value == -1 && (value=0); console.log('Found:',value); var value = someArray.indexOf(5); value == -1 && (value=0); console.log('Not Found:',value); 

Étant donné l’exemple de code à la question, il n’est pas clair comment il serait déterminé que 3 est ou n’est pas défini à l’index 0 de someArray . -1 renvoyé par .indexOf() serait utile dans ce cas, dans le but d’exclure une présumée non-correspondance qui pourrait être une correspondance.

Si 3 n’est pas inclus dans le tableau, -1 sera renvoyé. Nous pouvons append 1 au résultat de .indexOf() pour évaluer comme false pour le résultat étant -1 , suivi de || Opérateur OR et 0 . Lorsque value est référencé, soustrayez 1 pour obtenir l’index de l’élément du tableau ou -1 .

Ce qui revient à utiliser simplement .indexOf() et à vérifier la valeur -1 à une condition if . Ou, définir la value comme undefined pour éviter toute confusion possible quant au résultat réel de la condition évaluée relative à la référence d’origine.

 var someArray = [1,2,3]; var value = someArray.indexOf(3) + 1 || 1; console.log(value -= 1); var someArray = [1,2,3]; var value = someArray.indexOf(4) + 1 || 1; // how do we know that `4` is not at index `0`? console.log(value -= 1); var someArray = [1,2,3]; var value = someArray.indexOf(4) + 1 || void 0; // we know for certain that `4` is not found in `someArray` console.log(value, value = value || 0); 

Un ternaire est comme un sinon, si vous n’avez pas besoin de la partie autre, pourquoi pas un simple si à la place ..

 if ((value = someArray.indexOf(3)) < 0) value = 0;