javascript - operator - operador ternario php
Cómo escribir una expresión de operador ternario(también conocido como if) sin repetirse (16)
EDITAR: ¡Aquí está, la propuesta de Nullary-coalescing ahora en JavaScript!
Uso
||
const result = a ? a : ''fallback value'';
es equivalente a
const result = a || ''fallback value'';
Si lanzar
a
Boolean
devuelve
false
, el
result
se le asignará
''fallback value''
, de lo contrario, el valor de
a
.
Tenga en cuenta el caso límite
a === 0
, que se convierte en
false
y el
result
tomará (incorrectamente)
''fallback value''
.
Use trucos como este bajo su propio riesgo.
PD.
Los lenguajes como Swift tienen
nil-coalescing
operador de
nil-coalescing
(
??
), que tiene un propósito similar.
Por ejemplo, en Swift escribirías
result = a ?? "fallback value"
result = a ?? "fallback value"
que está bastante cerca del
const result = a || ''fallback value'';
de JavaScript
const result = a || ''fallback value'';
const result = a || ''fallback value'';
Por ejemplo, algo como esto:
var value = someArray.indexOf(3) !== -1 ? someArray.indexOf(3) : 0
¿Hay una mejor manera de escribir eso? Nuevamente, no estoy buscando una respuesta a la pregunta exacta anterior, solo un ejemplo de cuándo podría haber repetido operandos en expresiones de operador ternario ...
Creo que el
||
El operador se puede adaptar a
indexOf
:
var value = ((someArray.indexOf(3) + 1) || 1) - 1;
El valor devuelto se desplaza hacia arriba por 1, haciendo 0 desde -1, que es falso y, por lo tanto, se reemplaza por el segundo 1. Luego se desplaza hacia atrás.
Sin embargo, tenga en cuenta que la legibilidad es superior a evitar la repetición.
Dado el código de ejemplo en la pregunta, no está claro cómo se determinaría que
3
se establece o no en el índice
0
de
someArray
.
-1
devuelto por
.indexOf()
sería valioso en este caso, con el propósito de excluir una supuesta no coincidencia que podría ser una coincidencia.
Si
3
no está incluido en la matriz, se devolverá
-1
.
Podemos agregar
1
al resultado de
.indexOf()
para evaluar como
false
para que el resultado sea
-1
, seguido de
||
Operador
OR
y
0
.
Cuando se hace referencia al
value
, reste
1
para obtener el índice del elemento de la matriz o
-1
.
Lo que lleva de nuevo a simplemente usar
.indexOf()
y verificar
-1
en una condición
if
.
O bien, definir el
value
como
undefined
para evitar una posible confusión en cuanto al resultado real de la condición evaluada relacionada con la referencia original.
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);
El código debe ser legible, por lo que ser sucinto no debe significar ser conciso sea cual sea el costo, para eso debe volver a publicarlo en
https://codegolf.stackexchange.com/
, por lo que recomendaría usar una segunda variable local llamada
index
para maximizar la comprensión de lectura (con un costo de tiempo de ejecución mínimo también, lo noto):
var index = someArray.indexOf( 3 );
var value = index == -1 ? 0 : index;
Pero si realmente quieres reducir esta expresión, porque eres un sádico cruel con tus compañeros de trabajo o colaboradores del proyecto, entonces aquí hay 4 enfoques que puedes usar:
1: variable temporal en una instrucción
var
Puede usar la capacidad de la instrucción
var
para definir (y asignar) un segundo
index
variable temporal cuando se separa con comas:
var index = someArray.indexOf(3), value = index !== -1 ? index: 0;
2: función anónima de ejecución automática
Otra opción es una función anónima de ejecución automática:
// 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: operador de coma
También existe el infame "operador de coma" que admite JavaScript, que también está presente en C y C ++.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator
Puede usar el operador de coma cuando desee incluir varias expresiones en una ubicación que requiera una sola expresión.
Puede usarlo para introducir efectos secundarios, en este caso reasignando al
value
:
var value = ( value = someArray.indexOf(3), value !== -1 ? value : 0 );
Esto funciona porque el
var value
se interpreta primero (como es una declaración), y
luego
la asignación de
value
más interna y más a la izquierda, y luego la mano derecha del operador de coma, y luego el operador ternario, todo JavaScript legal.
4: reasignar en una subexpresión
El comentarista @IllusiveBrian señaló que el uso del operador de coma (en el ejemplo anterior) no es necesario si la asignación al
value
se usa como una subexpresión entre paréntesis:
var value = ( ( value = someArray.indexOf(3) ) !== -1 ? value : 0 );
Tenga en cuenta que el uso de negativos en expresiones lógicas puede ser más difícil de seguir para los humanos, por lo que todos los ejemplos anteriores se pueden simplificar para la lectura cambiando
idx !== -1 ? x : y
idx !== -1 ? x : y
a
idx == -1 ? y : x
idx == -1 ? y : x
:
var value = ( ( value = someArray.indexOf(3) ) == -1 ? 0 : value );
En realidad no, solo usa otra variable.
Su ejemplo generaliza a algo como esto.
var x = predicate(f()) ? f() : default;
Está probando un valor calculado y luego asigna ese valor a una variable si pasa algún predicado. La forma de evitar volver a calcular el valor calculado es obvia: use una variable para almacenar el resultado.
var computed = f();
var x = predicate(computed) ? computed : default;
Entiendo lo que quieres decir: parece que debería haber alguna forma de hacer esto que se vea un poco más limpia. Pero creo que esa es la mejor manera (idiomáticamente) de hacer esto. Si repitieras mucho este patrón en tu código por alguna razón, podrías escribir una pequeña función auxiliar:
var setif = (value, predicate, default) => predicate(value) ? value : default;
var x = setif(someArray.indexOf(3), x => x !== -1, 0)
Esta es una solución simple con
NOT bit
a
bit
y un valor predeterminado de
-1
que luego resulta en cero.
index = ~(~array.indexOf(3) || -1);
Funciona básicamente con un NOT doble a nivel de bit, que devuelve el valor original o un valor predeterminado, que después de aplicar NOT a nivel de bit devuelve cero.
Echemos un vistazo a la tabla de la verdad:
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
Hay dos maneras en que puedo ver al mirar su pregunta: desea reducir la longitud de la línea o específicamente evitar la repetición de una variable en un ternario. El primero es trivial (y muchos otros usuarios han publicado ejemplos):
var value = someArray.indexOf(3) !== -1 ? someArray.indexOf(3) : 0;
puede ser (y debería ser, dadas las llamadas a funciones) acortadas así:
var value = someArray.indexOf(3);
value = value !== -1 ? value : 0;
Si está buscando una solución más genérica que evite la repetición de una variable en un ternario, así:
var value = conditionalTest(foo) ? foo : bar;
donde
foo
solo aparece una vez.
Descartando soluciones de la forma:
var cad = foo;
var value = conditionalTest(foo) ? cad : bar;
como técnicamente correcto pero perdiendo el punto, entonces no tienes suerte. Hay operadores, funciones y métodos que poseen la sintaxis concisa que busca, pero tales construcciones, por definición, no son operadores ternarios .
Ejemplos:
javascript, usando
||
para devolver el RHS cuando el LHS está
falsey
:
var value = foo || bar; // equivalent to !foo ? bar : foo
Me gusta la respuesta de @ slebetman. El comentario debajo expresa preocupación acerca de que la variable esté en un "estado intermedio". Si esto es una gran preocupación para usted, le sugiero encapsularlo en una función:
function get_value(arr) {
var value = arr.indexOf(3);
if (value === -1) {
value = 0;
}
return value;
}
Entonces solo llama
var value = get_value( someArray );
Podrías hacer más funciones genéricas si tienes usos para ellas en otros lugares, pero no manipules de más si es un caso muy específico.
Pero para ser honesto, simplemente haría como @slebetman a menos que necesite volver a usarlo desde varios lugares.
Personalmente, creo que la mejor manera de hacer esto sigue siendo la buena declaración
if
:
var value = someArray.indexOf(3);
if (value === -1) {
value = 0;
}
Probablemente estés buscando un operador de fusión.
Afortunadamente, podemos aprovechar el prototipo de
Array
para crear uno:
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
Esto podría generalizarse aún más a su caso, agregando un parámetro a la función:
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
Puede usar la reasignación:
- inicializar variable a un valor
-
use la serialización del operador
&&
para la reasignación, porque si la primera condición es falsa, la segunda expresión no se evaluará
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);
Un ternario es como un if-else, si no necesita la parte else, ¿por qué no solo un if si?
if ((value = someArray.indexOf(3)) < 0) value = 0;
Use una función auxiliar:
function translateValue(value, match, translated) {
return value === match ? translated : value;
}
Ahora su código es muy legible y no hay repetición.
var value = translateValue(someArray.indexOf(3), -1, 0);
La jerarquía de las preocupaciones de codificación es:
- Correcto (incluido el rendimiento real o las preocupaciones de SLA)
- Claro
- Conciso
- Rápido
Todas las respuestas en la página hasta ahora parecen ser correctas, pero creo que mi versión tiene la mayor claridad, que es más importante que la concisión. Si no cuenta la función auxiliar, ya que puede reutilizarse, también es la más concisa. La sugerencia algo similar de usar una función auxiliar desafortunadamente usa una lambda que, para mí, simplemente oscurece lo que está haciendo. Para mí, una función más simple con un propósito que no toma una lambda, solo valores, es mucho mejor.
PD: si te gusta la sintaxis de ES6:
const translateValue = (value, match, translated) => value === match ? translated : value;
let value = translateValue(someArray.indexOf(3), -1, 0); // or const
Utilice una refactorización variable de extracto :
var index = someArray.indexOf(3);
var value = index !== -1 ? index : 0
Es incluso mejor con
const
lugar de
var
.
También podría hacer una extracción adicional:
const index = someArray.indexOf(3);
const condition = index !== -1;
const value = condition ? index : 0;
En la práctica, use nombres más significativos que
index
,
condition
y
value
.
const threesIndex = someArray.indexOf(3);
const threeFound = threesIndex !== -1;
const threesIndexOrZero = threeFound ? threesIndex : 0;
Yo personalmente prefiero dos variantes:
-
Puro si, como sugirió @slebetman
-
Función separada, que reemplaza el valor no válido por uno predeterminado, como en este ejemplo:
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
Para números
Puede usar la función
Math.max()
.
var value = Math.max( someArray.indexOf(''y''), 0 );
Mantendrá los límites del resultado desde
0
hasta el primer resultado mayor que
0
si ese es el caso.
Y si el resultado de
indexOf
es
-1
, devolverá 0 como es mayor que
-1
.
Para valores booleanos y booleanos
Para JS no existe una regla general AFAIK, especialmente porque se falsy valores falsy .
Pero si algo puede ayudarlo la mayor parte del tiempo es el operador o (
||
):
// Instead of
var variable = this_one === true ? this_one : or_this_one;
// you can use
var variable = this_one || or_this_one;
indexOf
tener mucho cuidado con esto, porque en su primer ejemplo,
indexOf
puede devolver
0
y si evalúa
0 || -1
0 || -1
devolverá
-1
porque
0
es un valor
falsy
.