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 ça? Encore une fois, je ne cherche pas une réponse à la question exacte ci-dessus, mais juste un exemple de cas où vous pourriez avoir répété des opérandes dans des expressions d'opérateur ternaire ...
Personnellement, je trouve que la meilleure façon de faire est toujours la bonne vieille déclaration if
var value = someArray.indexOf(3);
if (value === -1) {
value = 0;
}
Le code doit être lisible, donc être succinct ne signifie pas être concis, quel que soit le coût - pour que vous deviez republier vers https://codegolf.stackexchange.com/ - je vous recommanderais donc plutôt d'utiliser une deuxième variable locale. nommé index
pour optimiser la compréhension de la lecture (avec un coût d’exécution minimal, je remarque):
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 pour vos collègues ou collaborateurs du projet, voici 4 approches que vous pouvez utiliser:
var
Vous pouvez utiliser la capacité de l'instruction var
pour définir (et affecter) une deuxième variable temporaire index
, une fois séparée par des virgules:
var index = someArray.indexOf(3), value = index !== -1 ? index: 0;
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) );
Il y a aussi le fameux "opérateur de virgule" supporté par JavaScript, é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 seule expression.
Vous pouvez l’utiliser pour introduire des effets secondaires, dans ce cas en réaffectant à value
:
var value = ( value = someArray.indexOf(3), value !== -1 ? value : 0 );
Cela fonctionne parce que var value
est interprété en premier (comme c'est une déclaration), et then l'assignation value
la plus à gauche et la plus à l'intérieur, puis la droite de l'opérateur de virgule, puis l'opérateur ternaire - tout ce qui est légal. JavaScript.
Commentator @IllusiveBrian a souligné que l'utilisation de l'opérateur de 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. Par conséquent, la lecture de tous les exemples ci-dessus peut être simplifiée en remplaçant idx !== -1 ? x : y
par 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 c'est le cas. Et si le résultat de indexOf
est -1
, il retournera 0, car il est supérieur à -1
.
Pour les valeurs booléennes et booléennes-y
Pour JS, il n’ya pas de règle générale AFAIK spécialement parce que les valeurs de { falsy } _ sont évaluées.
Mais si quelque chose peut vous aider la plupart du temps, c'est l'opérateur or (||
):
// 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 renvoyer 0
et si vous évaluez 0 || -1
, il renverra -1
car 0
est une valeur falsy .
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 l'assignez à une variable si elle transmet un prédicat. La façon d'éviter de re-calculer 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 qu'il devrait y avoir un moyen de faire cela qui a l'air un peu plus propre. Mais je pense que c'est la meilleure façon (idiomatiquement) de faire cela. Si, pour une raison quelconque, vous répétiez souvent ce motif dans votre code, vous pourriez écrire une petite fonction d'assistance:
var setif = (value, predicate, default) => predicate(value) ? value : default;
var x = setif(someArray.indexOf(3), x => x !== -1, 0)
Utilisez ||
const result = a ? a : 'fallback value';
est équivalent à
const result = a || 'fallback value';
Si la conversion de a
en Boolean
renvoie false
, result
se verra attribuer 'fallback value'
, sinon la valeur de a
Soyez conscient du cas Edge a === 0
, qui transforme en false
et result
prendra (à tort) prendre 'fallback value'
. Utilisez des astuces comme celle-ci à vos risques et périls.
PS. Les langues telles que Swift ont nil-coalescing operator (??
), qui remplit des fonctions similaires. Par exemple, dans Swift, vous écririez result = a ?? "fallback value"
, ce qui est assez proche de const result = a || 'fallback value';
de JavaScript.
Utilisez un refactoring de variable extract :
var index = someArray.indexOf(3);
var value = index !== -1 ? index : 0
C'est encore mieux avec const
au lieu de var
. Vous pouvez aussi 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 index
, condition
et value
.
const threesIndex = someArray.indexOf(3);
const threeFound = threesIndex !== -1;
const threesIndexOrZero = threeFound ? threesIndex : 0;
Personnellement, je préfère deux variantes:
Pure si, comme @slebetman a suggéré
Fonction distincte, qui remplace la valeur non valide par la 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
Vous recherchez probablement un opérateur de coalescence. Heureusement, nous pouvons utiliser le 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 plus 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
J'aime la réponse de @ slebetman. Le commentaire en dessous exprime l'inquiétude que suscite la variable 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;
}
Ensuite, il suffit d'appeler
var value = get_value( someArray );
Vous pourriez faire des fonctions plus génériques si vous en avez déjà utilisé d'autres, mais ne faites pas trop d'ingénierie s'il s'agit d'un cas très spécifique.
Mais pour être honnête, je ne ferais que @slebetman à moins que je n’aie besoin de le réutiliser à plusieurs endroits.
Je peux envisager votre question de deux manières différentes: soit vous voulez réduire la longueur de ligne, soit vous voulez éviter de répéter une variable dans un ternaire. Le premier est trivial (et de nombreux autres utilisateurs ont posté 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 ceci:
var value = someArray.indexOf(3);
value = value !== -1 ? value : 0;
Si vous recherchez une solution plus générique qui empêche la répétition d'une variable dans un ternaire, procédez comme suit:
var value = conditionalTest(foo) ? foo : bar;
où foo
n'apparaît qu'une fois. Éliminer les solutions de la forme:
var cad = foo;
var value = conditionalTest(foo) ? cad : bar;
techniquement correct mais manquant le but, alors vous n'avez pas de chance. Il existe des opérateurs, des fonctions et des méthodes qui possèdent la syntaxe abrégée que vous recherchez, mais de telles constructions, par définition, ne sont pas des opérateurs ternaires .
Exemples:
javascript, en utilisant ||
pour renvoyer 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:
Jusqu'ici, toutes les réponses sur la page semblent être correctes, mais je pense que ma version est très 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’aide utilise malheureusement un lambda qui, pour moi, masque tout simplement son travail. Une fonction plus simple avec un objectif qui ne prend pas un lambda, mais des valeurs, est pour moi bien meilleure.
P.S. 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 l'opérateur ||
peut être adapté à indexOf
:
var value = ((someArray.indexOf(3) + 1) || 1) - 1;
La valeur renvoyée est augmentée de 1, faisant de 0 de -1, qui est falsey et est donc remplacée par la seconde 1. Ensuite, elle est décalée.
Cependant, gardez à l'esprit que la lisibilité est supérieure à la prévention des répétitions.
Il s’agit d’une solution simple avec bitwise NOT et une valeur par défaut de -1
qui résulte ultérieurement à zéro.
index = ~(~array.indexOf(3) || -1);
Cela fonctionne essentiellement avec un NOT bitwise au double, qui renvoie la valeur d'origine ou une valeur par défaut, qui après l'application du bit NOT 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:
&&
pour la réaffectation, car si la première condition est fausse, la seconde expression ne sera pas évaluéeEx.
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 dans Question, la manière dont il serait déterminé que 3
est défini ou non à l'index 0
de someArray
n'est pas claire. -1
renvoyé par .indexOf()
serait utile dans ce cas, afin d'exclure une non-correspondance présumée qui pourrait être une correspondance.
Si 3
n'est pas inclus dans le tableau, -1
sera renvoyé. Nous pouvons ajouter 1
au résultat de .indexOf()
pour l'évaluer comme étant false
, le résultat étant -1
, suivi de ||
OR
et de 0
. Lorsque value
est référencé, soustrayez 1
pour obtenir l'index de l'élément du tableau ou -1
.
Ce qui nous ramène à simplement utiliser .indexOf()
et à rechercher -1
dans une condition if
. Ou bien, définir value
comme undefined
pour éviter toute confusion 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 if-else, si vous n'avez pas besoin de l'autre partie, pourquoi ne pas en choisir un seul si.
if ((value = someArray.indexOf(3)) < 0) value = 0;