javascript - ¿Qué significa la construcción x=x || y?
Estoy depurando algo de JavaScript y no puedo explicar qué hace este ||:
function (title, msg) {
var title = title || 'Error';
var msg = msg || 'Error on Request';
}
¿Por qué este tipo está usando var title=title || 'ERROR'? A veces también lo veo sin una declaración var.
Respuesta #1
¿Qué es el operador de doble barra (||)?
El operador de doble barra (||) es el operador lógico OR. En la mayoría de los lenguajes funciona de la siguiente manera:
- Si el primer valor es
false, verifica el segundo valor. Si ese estrue, devuelvetruey si el segundo valor esfalse, devuelvefalse. - Si el primer valor es
true, siempre devuelvetrue, sin importar cuál sea el segundo valor.
Así que básicamente funciona así esta función:
function or(x, y) {
if (x) {
return true;
} else if (y) {
return true;
} else {
return false;
}
}
Si aún no entiendes, mira 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 de tipado débil. En este caso, significa que puedes usar el operador || con valores que no son booleanos. Aunque no tiene sentido, puedes usar este operador, por ejemplo, con una función y un objeto:
(function(){}) || {}
¿Qué pasa allí?
Si los valores no son booleanos, JavaScript realiza una conversión implícita a booleano. Esto significa que si el valor es falso (por ejemplo, 0, "", null, undefined (ver también Todos los valores falsos en JavaScript)), se tratará como false; de lo contrario, se tratará como true.
Entonces, el ejemplo anterior debería dar true, porque una función vacía es verdadera. Bueno, no lo hace. Devuelve la función vacía. Eso se debe a que 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 pasas un valor verdadero como x, devuelve x, es decir, un valor verdadero. Entonces, si lo usas más tarde en una 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 "O x o y es verdadero.".
Si x fuera falso, eitherXorY sería y. En este caso obtendrías "Either x or y is truthy." si y fuera verdadero; de lo contrario obtendrías "Neither x nor y is truthy".
La pregunta real
Ahora, cuando sabes cómo funciona el operador ||, probablemente puedas deducir por ti mismo qué significa x=x || y. Si x es verdadero, x se asigna a x, así que en realidad no pasa 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 te impide pasar un valor falso (que no necesariamente es undefined o null) como parámetro. Considera 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 pasas false como parámetro flagA (ya que es booleano, es decir, puede ser true o false)? Se convertiría en true. En este ejemplo, no hay forma de establecer flagA en false.
Sería una mejor idea verificar 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 puedes usar la sintaxis ES6 para los parámetros de función por defecto, pero ten en cuenta que no funciona en navegadores antiguos (como IE). Si quieres soportar estos navegadores, deberías transpilar tu código con Babel.
Véase también Operadores Lógicos en MDN.
Respuesta #2
Significa que el argumento title es opcional. Entonces, si llamas 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
se evalúa como true si a o b son true. Así que si a es verdadero, no necesitas comprobar b en absoluto. Esto se llama evaluación booleana de cortocircuito, así que:
var title = title || "Error";
básicamente verifica si title se evalúa como false. Si lo hace, "devuelve" "Error", de lo contrario devuelve title.
Respuesta #3
Si no se establece el título, use 'ERROR' como valor predeterminado.
Más genérico:
var foobar = foo || default;
Lee: Establece foobar en foo o default. Incluso podrías encadenar esto muchas veces:
var foobar = foo || bar || something || 42;
Respuesta #4
Explicando esto un poco más...
El operador || es el operador lógico o. 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 X es verdadero, el resultado siempre es verdadero. Así que, si sabemos que X es verdadero, no tenemos que comprobar Y en absoluto. Muchos lenguajes, por lo tanto, implementan evaluadores de "cortocircuito" para el or lógico (y and lógico viniendo desde la otra dirección). Comprobarán el primer elemento y, si eso es verdadero, 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 una diferencia potencialmente enorme si el segundo elemento es costoso de calcular.
¿Entonces qué tiene esto que ver con tu ejemplo?
var title = title || 'Error';
Veamos eso. El elemento title se pasa a tu función. En JavaScript, si no pasas un parámetro, por defecto toma un valor nulo. Además, en JavaScript, si tu variable tiene un valor nulo, los operadores lógicos la consideran como falsa. Así que 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. Si, sin embargo, no se le da un valor, es un valor nulo y por lo tanto falso. El operador lógico-or entonces evalúa la segunda expresión y devuelve 'Error' en su lugar. Así que ahora a la variable local se le asigna el valor 'Error'.
Esto funciona debido a la implementación de expresiones lógicas en JavaScript. No devuelve un valor booleano adecuado (true o false), sino que devuelve el valor que se le dio según algunas reglas sobre lo que se considera equivalente a true y lo que se considera equivalente a false. Consulta tu referencia de JavaScript para aprender qué considera JavaScript verdadero o falso en contextos booleanos.
Respuesta #5
|| 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"
Respuesta #6
Básicamente, verifica si el valor antes del || se evalúa como verdadero. Si es así, toma este valor, y si no, toma el valor después del ||.
Valores para los cuales tomará el valor después del || (hasta donde recuerdo):
- indefinida
- falsa
- '' (Nulo o cadena nula)
