ternario - operadores logicos javascript w3schools
¿Por qué los operadores lógicos en JavaScript se dejan asociativos? (3)
Para cualquier compilador decente, la asociatividad elegida de estos operadores es bastante irrelevante, y el código de salida será el mismo independientemente. Sí, el árbol de análisis es diferente, pero el código emitido no necesita serlo.
En todos los idiomas de la familia C que conozco (a los que también pertenece Javascript), los operadores lógicos se dejan asociativos. Entonces, la pregunta real es: ¿por qué los lenguajes tipo C definen los operadores lógicos como asociativos por la izquierda? Dado que la asociatividad elegida es irrelevante (en términos de semántica y en términos de eficiencia), mi sospecha es que se eligió la asociatividad más "natural" (como en "lo que la mayoría de los otros operadores usan"), aunque no lo hago. No tengo ninguna fuente para respaldar mis afirmaciones. Otra posible explicación es que los operadores asociativos a la izquierda toman menos espacio de pila para analizar utilizando un analizador LALR (lo que no es una gran preocupación en la actualidad, pero probablemente fue cuando C apareció).
Los operadores lógicos AND y OR son los únicos operadores perezosos en JavaScript junto con el operador condicional ternario. Se prueban para la evaluación de cortocircuito usando las siguientes reglas:
false && anything === false
true || anything === true
Esta es la misma forma en que se implementa en Haskell:
(&&) :: Bool -> Bool -> Bool
False && _ = False
True && x = x
(||) :: Bool -> Bool -> Bool
True || _ = True
False || x = x
Sin embargo, de acuerdo con MDN, los operadores lógicos en JavaScript son asociativos . Esto es contrario a la intuición. En mi humilde opinión deberían ser acertados asociativos. Haskell hace lo correcto. Los operadores lógicos en Haskell son asociativos de derecho:
infixr 3 &&
infixr 2 ||
Considera la siguiente expresión en Haskell:
False && True && True && True
Debido a que &&
es asociativo en Haskell, la expresión anterior es equivalente a:
False && (True && (True && True))
Por lo tanto, no importa qué evalúa la expresión (True && (True && True))
. Debido al primer False
la expresión completa se reduce a False
en un solo paso.
Ahora considera qué pasaría si &&
quedara asociativa. La expresión sería equivalente a:
((False && True) && True) && True
Ahora se necesitarían 3 reducciones para evaluar la expresión completa:
((False && True) && True) && True
(False && True) && True
False && True
False
Como puede ver, tiene más sentido para los operadores lógicos ser asociativos correctos. Esto me lleva a mi pregunta real:
¿Por qué los operadores lógicos en JavaScript se dejan asociativos? ¿Qué tiene que decir la especificación ECMAScript sobre esto? ¿Son los operadores lógicos en JavaScript en verdad asociativos? ¿Los documentos de MDN tienen información incorrecta sobre la asociatividad de los operadores lógicos?
Edición: Según la specification los operadores lógicos se dejan asociativos:
LogicalANDExpression = BitwiseORExpression
| LogicalANDExpression && BitwiseORExpression
LogicalORExpression = LogicalANDExpression
| LogicalORExpression || LogicalANDExpression
Respuesta simple: Imagina var i = nulo; if (i == null || i.getSomeValue ()) ... Cuando no se deja asociativo, la segunda prueba se evaluará primero y le dará una excepción.
Considere este código:
console.log( true || (false && true) ); // right associative (implicit)
console.log( (true || false) && true ); // left associative (Javascript)
Ambos ejemplos devuelven el mismo resultado, pero esa no es la razón para preocuparse por la asociatividad del operador. La razón por la que es relevante aquí se debe a la forma única en que los operadores lógicos determinan sus resultados. Aunque todas las permutaciones finalmente llegan a la misma conclusión final, el orden de los cálculos cambia, y eso puede tener grandes implicaciones para su código.
Entonces, ahora considera esto:
var name = "";
// ----------------------------------------
// Right associative
// ----------------------------------------
name = "albert einstein";
console.log("RIGHT : %s : %s", true || (false && updateName()), name);
// ----------------------------------------
// Left Associative
// ----------------------------------------
name = "albert einstein";
console.log("LEFT : %s : %s", (true || false) && updateName(), name);
function updateName() {
name = "charles manson";
return true;
}
La salida es:
RIGHT : true : albert einstein
LEFT : true : charles manson
Ambas expresiones devuelven verdadero, pero solo la versión asociada izquierda tuvo que llamar a updateName () para devolver una respuesta. La versión asociada correcta es diferente. Solo evalúa el primer argumento en (false && updateName())
porque el segundo argumento no puede cambiar el false
a true
.
Recuerda estos dos puntos:
- La precedencia del operador describe el orden de anidamiento de expresiones compuestas de diferentes tipos de operadores.
- La asociación de operadores describe el orden de anidamiento de las expresiones compuestas con la misma precedencia de operadores.
Tenga en cuenta que ninguno de los dos puntos anteriores cambia la forma en que se interpreta una expresión individual, solo la forma en que se interpretan las expresiones compuestas . La asociatividad ocurre en un nivel superior.
La asociatividad del operador, así como la precedencia del operador, tienen un enorme impacto en cómo se comporta un lenguaje. Comprender cuáles son esas diferencias es fundamental para poder usar y captar rápidamente las diferencias funcionales en diversos lenguajes de programación. Definitivamente obtienes mi aprobación por tu pregunta y espero que esto aclare un poco las cosas. Cuídate.