¿Qué significa la construcción x = x || y?


Estoy depurando algo de JavaScript, y no puedo explicar lo que esto || hace?

function (title, msg) {
  var title = title || 'Error';
  var msg   = msg || 'Error on Request';
}

¿Puede alguien darme una pista, por qué este tipo está usando var title = title || 'ERROR'? A veces lo veo sin una declaración var también.

Author: Michał Perłakowski, 2010-05-10

11 answers

Significa que el argumento title es opcional. Por lo tanto, si llama al método sin argumentos, utilizará un valor predeterminado de "Error".

Es una abreviatura para escribir:

if (!title) {
  title = "Error";
}

Este tipo de truco abreviado con expresiones booleanas también es común en Perl. Con la expresión:

a OR b

Evalúa a true si a o b es true. Así que si a es verdadero, no necesita verificar b en absoluto. Esto se denomina evaluación booleana de cortocircuito así:

var title = title || "Error";

Básicamente comprueba si title evalúa a false. Si lo hace, "devuelve" "Error", de lo contrario devuelve title.

 163
Author: cletus,
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-05-10 11:00:26

¿Qué es el operador de doble tubería (||)?

El operador de doble tubo (||) es el operador lógico OR . En la mayoría de los idiomas funciona de la siguiente manera:

  • Si el primer valor es false, comprueba el segundo valor. Si true, devuelve true y si es false, devuelve false.
  • Si el primer valor es true, siempre devuelve true, sin importar cuál sea el segundo valor.

Así que básicamente funciona como esta función:

function or(x, y) {
  if (x) {
    return true;
  } else if (y) {
    return true;
  } else {
    return false;
  }
}

Si todavía no entiendes, mira esta tabla: {[62]]}

      | true   false  
------+---------------
true  | true   true   
false | true   false  

En otras palabras, solo es falso cuando ambos valores son falsos.

¿Cómo es diferente en JavaScript?

JavaScript es un poco diferente, porque es un lenguaje de escritura flexible . En este caso significa que puede usar el operador || con valores que no son booleanos. Aunque no tiene sentido, puede usar este operador con, por ejemplo, una función y un objeto:

(function(){}) || {}

¿Qué sucede allí?

Si los valores no son booleanos, JavaScript hace una conversación implícita a booleano. Esto significa que si el valor es falsey (por ejemplo,0, "", null, undefined ( ver también Todos los falsey valores en JavaScript)), será tratada como false; de lo contrario, se trata como true.

Así que el ejemplo anterior debería dar true, porque la función vacía es verdadera. Bueno, no lo hace. Devuelve la función vacía. Eso es porque El operador || de JavaScript no funciona como escribí al principio. Funciona de la siguiente manera:

  • Si el primer valor es falsey, devuelve el segundo valor.
  • Si el primer valor es truthy, devuelve el primer valor.

Sorprendido? En realidad, es "compatible" con el operador tradicional ||. Podría escribirse como la siguiente función:

function or(x, y) {
  if (x) {
    return x;
  } else {
    return y;
  }
}

Si pasa un valor de verdad como x, se devuelve x, es decir, un valor truth. Así que si lo usas más tarde en la cláusula if:

(function(x, y) {
  var eitherXorY = x || y;
  if (eitherXorY) {
    console.log("Either x or y is truthy.");
  } else {
    console.log("Neither x nor y is truthy");
  }
}(true/*, undefined*/));

Obtienes "Either x or y is truthy.".

Si x era falsey, eitherXorY sería y. En este caso obtendrías el "Either x or y is truthy." si y fuera veraz; de lo contrario obtendrías "Neither x nor y is truthy".

La pregunta real

Ahora, cuando sabes cómo funciona el operador ||, probablemente puedas entender por ti mismo lo que significa x = x || y. Si x es veraz, x se asigna a x, por lo que en realidad no sucede nada; de lo contrario y se asigna a x. Se utiliza comúnmente para definir parámetros predeterminados en funciones. Sin embargo, a menudo se considera una mala práctica de programación , porque le impide pasar un valor falsey (que no es necesariamente undefined o null) como parámetro. Considere el siguiente ejemplo:

function badFunction(/* boolean */flagA) {
  flagA = flagA || true;
  console.log("flagA is set to " + (flagA ? "true" : "false"));
}

Parece válido a primera vista. Sin embargo, ¿qué pasaría si pasaras false como parámetro flagA (ya que es booleano, es decir, puede ser true o false)? It se convertiría en true. En este ejemplo, no hay manera de establecer flagA a false.

Sería una mejor idea comprobar explícitamente si flagA es undefined, así:

function goodFunction(/* boolean */flagA) {
  flagA = typeof flagA !== "undefined" ? flagA : true;
  console.log("flagA is set to " + (flagA ? "true" : "false"));
}

Aunque es más largo, siempre funciona y es más fácil de entender.


También puede usar la sintaxis ES6 para los parámetros de función predeterminados, pero tenga en cuenta que no funciona en navegadores más antiguos (como IE). Si desea admitir estos navegadores, debe transpilar su código con Babel .

Véase también Operadores lógicos en MDN.

 122
Author: Michał Perłakowski,
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-03-05 09:56:35

Si title no está definido, utilice 'ERROR' como valor predeterminado.

Más genérico:

var foobar = foo || default;

Dice: Establece foobar en foo o default. Incluso podrías encadenar esto muchas veces:

var foobar = foo || bar || something || 42;
 24
Author: ericteubert,
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-09-18 14:57:00

Explicando esto un poco más...

El operador || es el operador lógico-or. El resultado es true si la primera parte es cierto y es cierto si la segunda parte es cierto y es verdadera si ambas partes son verdaderas. Para mayor claridad, aquí está en una tabla:

 X | Y | X || Y 
---+---+--------
 F | F |   F    
---+---+--------
 F | T |   T    
---+---+--------
 T | F |   T    
---+---+--------
 T | T |   T    
---+---+--------

¿Ahora notas algo aquí? Si X es true, el resultado siempre es true. Así que si sabemos que X es verdad no tenemos que comprobar Y en absoluto. Por lo tanto, muchos idiomas implementan evaluadores de "cortocircuito" para lógico - or (y lógico-and viniendo de la otra dirección). Comprueban el primer elemento y si eso es cierto no se molestan en comprobar el segundo en absoluto. El resultado (en términos lógicos) es el mismo, pero en términos de ejecución hay potencialmente una gran diferencia si el segundo elemento es caro de calcular.

Entonces, ¿qué tiene esto que ver con tu ejemplo?

var title   = title || 'Error';

Veamos eso. El elemento title se pasa a su función. En JavaScript si no lo haces si pasa un parámetro, el valor predeterminado es null. También en JavaScript si su variable es un valor null, los operadores lógicos consideran que es false. Así que si esta función se llama con un título dado, es un valor no falso y por lo tanto asignado a la variable local. Si, sin embargo, no se le da un valor, es un valor nulo y por lo tanto falso. El operador lógico-or evalúa la segunda expresión y devuelve 'Error' en su lugar. Así que ahora a la variable local se le da el valor "Error".

Esto funciona debido a la implementación de expresiones lógicas en JavaScript. No devuelve un valor booleano propio (true o false), sino que devuelve el valor que se le dio bajo algunas reglas en cuanto a lo que se considera equivalente a true y lo que se considera equivalente a false. Busque su referencia de JavaScript para aprender lo que JavaScript considera verdadero o falso en contextos booleanos.

 13
Author: JUST MY correct OPINION,
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-05-10 11:14:53

Double pipe significa "O"lógico. Este no es realmente el caso cuando el "parámetro no establecido", ya que estrictamente en el javascript si tiene código como este:

function foo(par) {
}

Luego llama

foo()
foo("")
foo(null)
foo(undefined)
foo(0)

No Son equivalentes.

Double pipe (||) lanzará el primer argumento a booleano y si el booleano resultante es true - do la asignación de lo contrario asignará la parte correcta.

Esto es importante si se comprueba el parámetro unset.

Digamos que tenemos una función setSalary que tiene un parámetro opcional. Si el usuario no proporciona el parámetro, se debe usar el valor predeterminado de 10.

Si haces la comprobación de esta manera:

function setSalary(dollars) {
    salary = dollars || 10
}

Esto dará un resultado inesperado en llamada como

setSalary(0) 

Todavía establecerá el 10 siguiendo el flujo descrito anteriormente.

 7
Author: Juriy,
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-05-10 11:11:38

Básicamente comprueba si el valor antes del || se evalúa como verdadero, si es así, toma este valor, si no, toma el valor después del ||.

Valores para los que tomará el valor después de | / (por lo que recuerdo):

  • indefinido
  • false
  • 0
  • " (Cadena nula o nula)
 6
Author: Morfildur,
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
2014-07-17 10:33:32

Operador de tubería doble

¿Es útil este ejemplo?

var section = document.getElementById('special');
if(!section){
     section = document.getElementById('main');
}

También Puede ser

var section = document.getElementById('special') || document.getElementById('main');
 4
Author: choise,
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-05-10 11:01:22

Mientras que la respuesta de Cletus es correcta, creo que se deben agregar más detalles con respecto a "evalúa a falso" en JavaScript.

var title = title || 'Error';
var msg   = msg || 'Error on Request';

No es solo verificar si se ha proporcionado title/msg, sino también si cualquiera de ellos es falso. es decir, una de las siguientes:

  • falso.
  • 0 (cero)
  • "" (cadena vacía)
  • null.
  • indefinido.
  • NaN (un valor de Número especial que significa No-un-Número!)

Así que en la línea

var title = title || 'Error';

Si el título es verdadero (es decir, no falso, entonces title = "titleMessage" etc.) entonces el operador booleano O ( | / ) ha encontrado un valor 'verdadero', lo que significa que se evalúa como verdadero, por lo que cortocircuita y devuelve el valor verdadero (title).

Si title es falsy (es decir, uno de la lista anterior), entonces el operador booleano O (||) ha encontrado un valor 'false', y ahora necesita evaluar la otra parte del operador, 'Error' , que evalúa a true, y es por lo tanto regresó.

También parecería (después de algunos experimentos rápidos en la consola firebug) si ambos lados del operador evalúan false, devuelve el segundo operador 'falsy'.

Es decir,

return ("" || undefined)

Devuelve undefined, esto es probablemente para permitirle usar el comportamiento sobre el que se pregunta en esta pregunta cuando intenta predeterminar el título/mensaje a "". es decir, después de ejecutar

var foo = undefined
foo = foo || ""

Foo se establecería en ""

 3
Author: Azrantha,
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-05-23 11:47:29

Para añadir alguna explicación a todo lo dicho antes que yo, debería darte algunos ejemplos para entender conceptos lógicos.

var name = false || "Mohsen"; # name equals to Mohsen
var family = true || "Alizadeh" # family equals to true

Significa que si el lado izquierdo evaluado como una declaración verdadera, se terminará y el lado izquierdo se devolverá y se asignará a la variable. en otros casos se devolverá y asignará el lado derecho.

Y el operador tiene la estructura opuesta como abajo.

var name = false && "Mohsen" # name equals to false
var family = true && "Alizadeh" # family equals to Alizadeh
 3
Author: Mohsen Alizadeh,
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-01-14 21:34:43

Cita: "¿Qué significa el constructo x = x / / y?"

Asignar un valor predeterminado.

Esto significa proporcionando un valor predeterminado de y a x, en el caso x todavía está esperando su valor, pero no lo ha recibido todavía o se omitió deliberadamente para volver a un valor predeterminado.

 2
Author: Bekim Bacaj,
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-05-09 13:34:18

Y tengo que añadir una cosa más: Este pedazo de taquigrafía es una abominación. Utiliza mal una optimización accidental del intérprete (no molestando con la segunda operación si la primera es veraz) para controlar una asignación. Ese uso no tiene nada que ver con el propósito del operador. No creo que deba usarse nunca.

Prefiero el operador ternario para la inicialización, eg,

var title = title?title:'Error';

Esto usa una operación condicional de una línea para su propósito correcto. Todavía suena juegos antiestéticos con truthiness pero, eso es Javascript para usted.

 -4
Author: tqwhite,
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-04-29 19:43:33