JavaScript O ( / / ) explicación de asignación de variables


Dado este fragmento de JavaScript...

var a;
var b = null;
var c = undefined;
var d = 4;
var e = 'five';

var f = a || b || c || d || e;

alert(f); // 4

¿Puede alguien por favor explicarme cómo se llama esta técnica (mi mejor conjetura está en el título de esta pregunta!)? ¿Y cómo / por qué funciona exactamente?

Mi entendimiento es que a la variable f se le asignará el valor más cercano (de izquierda a derecha) de la primera variable que tenga un valor que no sea nulo o indefinido, pero no he logrado encontrar mucho material de referencia sobre esta técnica y he visto que se utiliza un mucho.

Además, ¿esta técnica es específica de JavaScript? Sé que hacer algo similar en PHP resultaría en que f tuviera un verdadero valor booleano, en lugar del valor de d en sí.

Author: Bergi, 2010-01-20

12 answers

Véase evaluación de cortocircuitos para la explicación. Es una forma común de implementar estos operadores; no es exclusivo de JavaScript.

 174
Author: unwind,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-02-05 20:43:26

Esto se hace para asignar un valor predeterminado, en este caso el valor de y, si x variable falsy.

Los operadores booleanos en JavaScript pueden devolver un operando, y no siempre un resultado booleano como en otros lenguajes.

El operador lógico OR (||) devuelve el valor de su segundo operando, si el primero es falsy, de lo contrario se devuelve el valor del primer operando.

Por ejemplo:

"foo" || "bar"; // returns "foo"
false || "bar"; // returns "bar"

Falsy los valores son aquellos que coaccionan a false cuando se usan en contexto booleano, y son 0, null, undefined, una cadena vacía, NaN y por supuesto false.

 152
Author: CMS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-21 20:11:51

Javacrit usa evaluación de cortocircuito para operadores lógicos || y &&. Sin embargo, es diferente a otros lenguajes en que devuelve el resultado del último valor que detuvo la ejecución, en lugar de un valor true o false.

Los siguientes valores se consideran falsos en JavaScript.

  • false
  • null
  • "" (cadena vacía)
  • 0
  • Nan
  • indefinido

Ignorando el reglas de precedencia del operador, y manteniendo las cosas simples, los siguientes ejemplos muestran qué valor detuvo la evaluación, y se devuelve como resultado.

false || null || "" || 0 || NaN || "Hello" || undefined // "Hello"

Los primeros 5 valores hasta NaN son falsos, por lo que todos se evalúan de izquierda a derecha, hasta que cumple con el primer valor de verdad - "Hello" que hace que toda la expresión sea verdadera, por lo que cualquier cosa más arriba no se evaluará, y "Hello" se devuelve como resultado de la expresión. Del mismo modo, en este caso:

1 && [] && {} && true && "World" && null && 2010 // null

Los primeros 5 valores son todos truthy y se evalúan hasta que cumple con el primer valor falsy (null) que hace que la expresión false, por lo que 2010 ya no se evalúa, y null se devuelve como resultado de la expresión.

El ejemplo que has dado es hacer uso de esta propiedad de JavaScript para realizar una asignación. Se puede usar en cualquier lugar donde necesite obtener el primer valor verdadero o falso entre un conjunto de valores. Este código a continuación asignará el valor "Hello" a b ya que hace más fácil asignar un valor predeterminado, en lugar de hacer comprobaciones if-else.

var a = false;
var b = a || "Hello";

Se podría llamar al siguiente ejemplo una explotación de esta característica, y creo que hace que el código sea más difícil de leer.

var messages = 0;
var newMessagesText = "You have " + messages + " messages.";
var noNewMessagesText = "Sorry, you have no new messages.";
alert((messages && newMessagesText) || noNewMessagesText);

Dentro de la alerta, comprobamos si messages es falso, y si es así, entonces evaluamos y devolvemos noNewMessagesText, de lo contrario evaluamos y devolvemos newMessagesText. Dado que es falso en este ejemplo, nos detenemos en noNewMessagesText y alert "Sorry, you have no new messages.".

 104
Author: Anurag,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-14 13:37:39

Las variables Javascript no se escriben, por lo que a f se le puede asignar un valor entero aunque se haya asignado a través de operadores booleanos.

A F se le asigna el valor más cercano que es no equivalente a false. Así que 0, false, null, undefined, se pasan por encima:

alert(null || undefined || false || '' || 0 || 4 || 'bar'); // alerts '4'
 41
Author: Alsciende,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-06 09:39:03

No hay magia en ello. Las expresiones booleanas como a || b || c || d se evalúan perezosamente. Interpeter busca el valor de a, es indefinido por lo que es falso por lo que se mueve en, entonces ve b que es nulo, que todavía da resultado falso por lo que se mueve en, entonces ve c - misma historia. Finalmente ve d y dice 'huh, no es null, así que tengo mi resultado' y lo asigna a la variable final.

Este truco funcionará en todos los lenguajes dinámicos que hacen evaluaciones perezosas de cortocircuito de expresiones booleanas. En lenguajes estáticos no se compila (error de tipo). En lenguajes que están ansiosos por evaluar expresiones booleanas, devolverá un valor lógico (es decir, true en este caso).

 30
Author: Marcin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-20 10:58:21

Esta pregunta ya ha recibido varias buenas respuestas.

En resumen, esta técnica está aprovechando una característica de cómo se compila el lenguaje. Es decir, JavaScript "cortocircuita" la evaluación de los operadores booleanos y devolverá el valor asociado con el primer valor de variable no falsa o lo que contenga la última variable. Vea la explicación de Anurag de aquellos valores que evaluarán como falsos.

El uso de esta técnica no es una buena práctica para varias razones, sin embargo.

  1. Legibilidad del código: Esto está usando operadores booleanos, y si el comportamiento de cómo se compila no se entiende, entonces el resultado esperado sería un valor booleano.
  2. Estabilidad: Esto está usando una característica de cómo se compila el lenguaje que es inconsistente en varios idiomas, y debido a esto es algo que potencialmente podría ser objetivo para el cambio en el futuro.
  3. Características documentadas: Existe una alternativa eso satisface esta necesidad y es consistente en más idiomas. Este sería el operador ternario:

    () ? valor 1: Valor 2.

Usar el operador ternario requiere un poco más de escritura, pero distingue claramente entre la expresión booleana que se evalúa y el valor que se asigna. Además, se puede encadenar, por lo que los tipos de asignaciones predeterminadas que se realizan anteriormente se pueden volver a crear.

var a;
var b = null;
var c = undefined;
var d = 4;
var e = 'five';

var f =  ( a ) ? a : 
                ( b ) ? b :
                       ( c ) ? c :
                              ( d ) ? d :
                                      e;

alert(f); // 4
 9
Author: WSimpson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-03 14:19:53

Devuelve la salida primer valor verdadero.

Si todos son falsos devuelve el último valor falso.

Ejemplo: -

  null || undefined || false || 0 || 'apple'  // Return apple
 5
Author: Arshid KV,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-15 12:20:02

Está estableciendo la nueva variable (z) ya sea al valor de x si es "truth" (distinto de cero, un objeto/matriz/función/lo que sea) o y de lo contrario. Es una forma relativamente común de proporcionar un valor predeterminado en caso de que x no exista.

Por ejemplo, si tiene una función que toma un parámetro opcional de devolución de llamada, podría proporcionar una devolución de llamada predeterminada que no hace nada:

function doSomething(data, callback) {
    callback = callback || function() {};
    // do stuff with data
    callback(); // callback will always exist
}
 4
Author: Matthew Crumley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-21 20:13:32

Significa que si x se establece, el valor para z será x, de lo contrario si y se establece entonces su valor se establecerá como el valor de z.

Es lo mismo que

if(x)
  z = x;
else
  z = y;

Es posible porque los operadores lógicos en JavaScript no devuelven valores booleanos sino el valor del último elemento necesario para completar la operación (en una oración OR sería el primer valor no falso, en una oración AND sería el último). Si la operación falla, entonces false es devolver.

 1
Author: Andris,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-06-21 20:23:20

Se llama operador de cortocircuito.

La evaluación de cortocircuito dice que el segundo argumento se ejecuta o evalúa solo si el primer argumento no es suficiente para determinar el valor de la expresión. cuando el primer argumento de la función OR (||) se evalúa como true, el valor general debe ser true.

También podría usarse para establecer un valor predeterminado para el argumento de la función.`

function theSameOldFoo(name){ 
  name = name || 'Bar' ;
  console.log("My best friend's name is " + name);
}
theSameOldFoo();  // My best friend's name is Bar
theSameOldFoo('Bhaskar');  // My best friend's name is Bhaskar`
 1
Author: Vijay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-22 11:17:19

Evaluará X y, si X no es nulo, la cadena vacía, o 0 (falso lógico), entonces lo asignará a z. Si X es nulo, la cadena vacía, o 0 (falso lógico), entonces asignará y a z.

var x = '';
var y = 'bob';
var z = x || y;
alert(z);

Mostrará 'bob';

 0
Author: tvanfosson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-27 17:02:22

De acuerdo con el Blog de Bill Higgins post; el lenguaje lógico O de asignación de Javascript (Feb. 2007), este comportamiento es cierto a partir de v1.2 (al menos)

También sugiere otro uso para él (citado): " normalización ligera de las diferencias entre navegadores "

// determine upon which element a Javascript event (e) occurred
var target = /*w3c*/ e.target || /*IE*/ e.srcElement;
 0
Author: Alon Brontman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-12-21 18:14:25