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

250

Estoy depurando algunos JavaScript y no puedo explicar qué ||hace esto .

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

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

opHASnoNAME
fuente
44
La gente ya ha respondido esto ... pero sea extremadamente consciente del hecho de que el segundo valor se elige si el primer valor es falsy, no SOLO undefined. La cantidad de veces que he visto doWeDoIt = doWeDoIt || truees suficiente para hacerme llorar. (es decir doWeDoIt, ahora nunca lo será false)
Matt
44
Para aquellos con experiencia en C #, el operador de doble tubo es equivalente al operador de fusión nula ??. Javascript evalúa objetos no nulos como true (o mejor evalúa objetos nulos como falsos)
usr-local-ΕΨΗΕΛΩΝ
3
No se sienta mal: JS es el único lenguaje tonto que permite esta codificación horrible ... eso y enseña que es apropiado anidar cada función en líneas de código y tirarlas, haciéndolas desechables e inutilizables por segunda vez. :) Tengo 30 años en la codificación y dejé de tocar JS hasta hace poco, y siento tu dolor, todo lo que puedo decir es que tengas una hoja de cheets "no tiene sentido, solo está en JS", es la única forma en que ' he pasado! :)
Collin Chaffin
1
Considere cambiar la respuesta aceptada a mi respuesta .
Michał Perłakowski

Respuestas:

211

Significa que el titleargumento es opcional. Entonces, si llama al método sin argumentos, usará un valor predeterminado de "Error".

Es una forma abreviada de 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

se evalúa truesi ya sea ao bes true. Entonces, si aes cierto, no necesita verificarlo ben absoluto. Esto se llama evaluación booleana de cortocircuito, entonces:

var title = title || "Error";

básicamente comprueba si se titleevalúa a false. Si lo hace, "regresa" "Error", de lo contrario, regresa title.

cletus
fuente
3
Lamento ser quisquilloso, pero el argumento no es opcional, el argumento está marcado
themightybun
44
Esta NO es la respuesta y estoy de acuerdo con el último comentario, ni siquiera es opcional. Ninguna parte de esta respuesta es correcta, incluso la referencia de Perl, ya que la declaración de Perl realmente tiene sentido y se evalúa de una manera completamente diferente. El JS se evalúa en un método lógico booleano mucho más "convertido" que yo también encuentro mucho más confuso para leer / escribir. La respuesta a continuación titulada "¿Cuál es el operador de doble tubo" es en realidad una respuesta correcta.
Collin Chaffin
198

¿Qué es el operador de doble tubo ( ||)?

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

  • Si el primer valor es false, verifica el segundo valor. Si es así true, vuelve truey si lo es false, vuelve false.
  • Si el primer valor es true, siempre regresa true, sin importar cuál sea el segundo valor.

Entonces, básicamente funciona como esta función:

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

Si aún no lo comprende, mire esta tabla:

      | 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 poco escrito . 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(){}) || {}

Que pasa alli

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

Entonces el ejemplo anterior debería dar true, porque la función vacía es verdadera. Pues no. 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 verdadero , 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, devuelve x, es decir, un valor de verdad. Entonces, si lo usa más adelante en la ifcláusula:

(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*/));

se obtiene "Either x or y is truthy.".

Si xfuera falsey, eitherXorYlo sería y. En este caso, obtendría el "Either x or y is truthy."if yera verdadero; de lo contrario lo conseguirí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 x = x || ysignifica. Si xes veraz, xse le asigna x, por lo que en realidad no sucede nada; de lo contrario yestá asignado a x. Se usa comúnmente para definir parámetros predeterminados en funciones. Sin embargo, a menudo se considera una mala práctica de programación , ya que evita que pase un valor falsey (que no es necesariamente undefinedo 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 pasara falsecomo flagAparámetro (ya que es booleano, es decir, puede ser trueo false)? Se convertiría true. En este ejemplo, no hay manera de establecer flagAa false.

Sería una mejor idea verificar explícitamente si flagAes undefinedasí:

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 antiguos (como IE). Si desea admitir estos navegadores, debe transpilar su código con Babel .

Ver también Operadores lógicos en MDN .

Michał Perłakowski
fuente
13
+1: con mucho, la respuesta más correcta y completa. Y, para aquellos con esta pregunta (algunos de nosotros, codificadores veteranos nuevos en JS incluidos), sin duda deberíamos enfocarnos al máximo en toda esta respuesta en esta línea: "Aunque no tiene sentido" porque este "tipeado" simplemente nunca tendrá sentido a aquellos de nosotros que crecimos sin ella. Para nosotros, un operador booleano es solo eso y SOLO eso ... y cualquiera que haya pensado que sería una buena idea tener que detenerse y pensar en una conversión extraña de valores no booleanos a booleanos mientras lee / escribe código , olvidé tomar sus medicamentos ese día! :)
Collin Chaffin
2
+1, en pocas palabras: title = title || 'Error'significaif (title) { title = title; } else { title = 'Error'; }
Andre Elrico
De hecho, no estoy de acuerdo con la línea "aunque no tiene sentido". Entiendo que la línea no se compilaría en C, por ejemplo, pero se entiende bien si viniste de Ruby, por ejemplo, o incluso Groovy. En Ruby podrías expresarlo aún más corto, como title ||= 'Error'.
Elliot Nelson
28

Si el título no está configurado, use 'ERROR' como valor predeterminado.

Más genérico:

var foobar = foo || default;

Lee: establece foobar en fooo default. Incluso podrías encadenar esto muchas veces:

var foobar = foo || bar || something || 42;
ericteubert
fuente
1
Lo encontré confuso porque las variables tienen el mismo nombre. Mucho más fácil cuando no lo hacen.
Norbert Norbertson
14

Explicando esto un poco más ...

El ||operador es el oroperador lógico . El resultado es verdadero si la primera parte es verdadera y es verdadero si la segunda parte es verdadera y es verdadero 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 Xes verdadero, el resultado siempre es verdadero. Entonces, si sabemos que eso Xes cierto, no tenemos que verificarlo Yen absoluto. Muchos lenguajes implementan así evaluadores de "cortocircuito" para lógica or(y lógica que andproviene de la otra dirección). Comprueban el primer elemento y, si eso es cierto, no se molestan en comprobar el segundo. El resultado (en términos lógicos) es el mismo, pero en términos de ejecución existe una gran diferencia si el segundo elemento es costoso de calcular.

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

var title   = title || 'Error';

Miremos eso. El titleelemento se pasa a su función. En JavaScript, si no pasa un parámetro, su valor predeterminado es nulo. También en JavaScript, si su variable es un valor nulo, los operadores lógicos lo consideran falso. Entonces, si esta función se llama con un título dado, es un valor no falso y, por lo tanto, se asigna a la variable local. Sin embargo, si no se le da un valor, es un valor nulo y, por lo tanto, falso. El oroperador lógico luego evalúa la segunda expresión y devuelve 'Error' en su lugar. Entonces ahora la variable local recibe el valor 'Error'.

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

SOLO MI OPINIÓN correcta
fuente
8

La tubería doble significa "OR" lógico. Este no es realmente el caso cuando el "parámetro no está configurado", ya que estrictamente en JavaScript si tiene un código como este:

function foo(par) {
}

Luego llama

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

No son equivalentes.

Double pipe (||) convertirá el primer argumento en booleano y, si el booleano resultante es verdadero, haga la asignación; de lo contrario, asignará la parte correcta.

Esto es importante si verifica el parámetro no establecido.

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 el chequeo así:

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

Esto dará un resultado inesperado en llamadas como

setSalary(0) 

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

Juriy
fuente
8

Básicamente verifica si el valor antes de || se evalúa como verdadero, en caso afirmativo, toma este valor, si no, toma el valor después de ||.

Valores para los cuales tomará el valor después de || (hasta donde recuerdo):

  • indefinido
  • falso
  • 0 0
  • '' (Cadena nula o nula)
Morfildur
fuente
1
falso || nulo || indefinido || 0 || '' || 'se le olvidó nulo'
Dziamid
7

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

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

No es solo verificar si se ha proporcionado título / mensaje, sino también si alguno de ellos es falso . es decir, uno de los siguientes:

  • falso.
  • 0 (cero)
  • "" (cuerda vacía)
  • nulo.
  • indefinido
  • NaN (un valor de número especial que significa ¡No es un número!)

Entonces en la linea

var title = title || 'Error';

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

Si el título es falso (es decir, uno de la lista anterior), el operador booleano OR (||) ha encontrado un valor 'falso' y ahora necesita evaluar la otra parte del operador, 'Error', que se evalúa como verdadero y, por lo tanto, se devuelve.

También parecería (después de una rápida experimentación con la consola Firebug) si ambos lados del operador evalúan como falso, devuelve el segundo operador 'falso'.

es decir

return ("" || undefined)

devuelve indefinido, esto es probablemente para permitirle usar el comportamiento sobre el que se preguntó en esta pregunta al intentar asignar un título / mensaje predeterminado a "". es decir, después de correr

var foo = undefined
foo = foo || ""

foo se establecería en ""

Azrantha
fuente
5

operador de doble tubo

¿Es útil este ejemplo?

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

puede también ser

var section = document.getElementById('special') || document.getElementById('main');
elegir
fuente
4

Para agregar alguna explicación a todo lo dicho antes que yo, debo darle algunos ejemplos para comprender los 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 se evalúa como una declaración verdadera, se terminará y el lado izquierdo se devolverá y se asignará a la variable. en otros casos, el lado derecho será devuelto y asignado.

Y el operador tiene la estructura opuesta como a continuación.

var name = false && "Mohsen" # name equals to false
var family = true && "Alizadeh" # family equals to Alizadeh
Mohsen Alizadeh
fuente
3

|| es el operador booleano OR. Como en JavaScript, undefined, null, 0, false se consideran valores falsos .

Simplemente significa

true || true = true
false || true = true
true || false = true
false || false = false

undefined || "value" = "value"
"value" || undefined = "value"
null || "value" = "value"
"value" || null = "value"
0 || "value" = "value"
"value" || 0 = "value"
false || "value" = "value"
"value" || false = "value"
Shivang Gupta
fuente
2

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

Asignación de un valor predeterminado.

Esto significa proporcionar un valor predeterminado de y a x , en caso de que x todavía esté esperando su valor pero aún no lo haya recibido o se haya omitido deliberadamente para volver a un valor predeterminado.

Bekim Bacaj
fuente
Ese es el significado exacto de la construcción y el único significado de la misma. Y fue ampliamente como una subrutina en las funciones de escritura que se podían obtener como prototipos, funciones independientes y también como métodos prestados para ser aplicados en otro elemento. Donde su principal y único deber era modificar la referencia del objetivo. Ejemplo: function getKeys(x) { x = x || this ; .... }que podría usarse sin modificación como una función independiente, como un método de propiedad en prototipos y como un método de un elemento que puede obtener otro elemento como argumento como `[element] .getKeys (anotherElement);`
Bekim Bacaj
-5

Y tengo que agregar una cosa más: este poco de taquigrafía es una abominación. Hace un mal uso de una optimización accidental del intérprete (sin molestarse con la segunda operación si la primera es verdadera) para controlar una asignación. Ese uso no tiene nada que ver con el propósito del operador. No creo que deba usarse alguna vez.

Prefiero el operador ternario para la inicialización, por ejemplo,

var title = title?title:'Error';

Esto utiliza una operación condicional de una línea para su propósito correcto. Todavía juega juegos antiestéticos con veracidad, pero eso es Javascript para ti.

tqwhite
fuente