Precedencia de operadores

La precedencia de operadores determina el orden en el cual los operadores son evaluados uno respecto del otro. Los operadores con mayor precedencia se convierten en los operandos de los operadores con menor precedencia.

Pruébalo

Precedencia y Asociatividad

Considere la expresión descrita debajo. Note que OP1 y OP2 son ambos ejemplos de operadores.

js
a OP1 b OP2 c

Si OP1 y OP2 tienen diferente niveles de precedencia (véase la tabla debajo), el operador con la precedencia más alta va primero y la asociatividad no importa. Observe como la multiplicación tiene mayor precedencia que la suma y se ejecuta primero, a pesar de que la suma se escribe primero en el código.

js
console.log(3 + 10 * 2); // muestra 23
console.log(3 + (10 * 2)); // muestra 23 porque los paréntesis son superfluos
console.log((3 + 10) * 2); // muestra 26 porque los paréntesis cambian el orden

La asociatividad a la izquierda (de izquierda a derecha) significa que es procesado como (a OP1 b) OP2 c, mientras que la asociatividad a la derecha (de derecha a izquierda) significa que es interpretado como a OP1 (b OP2 c). Los opearadores de asignación son de asociatividad a la derecha, entonces se puede escribir:

js
a = b = 5; // es igual a escribir a = (b = 5);

con el resultado esperado de que a y b obtienen el valor 5. Esto es porque el operador de asignación retorna el valor que es asignado. Primero, b es establecido en 5. Luego a también es establecida en 5, el valor de retorno de b = 5, también conocido como el operando de la derecha de la asignación.

Como otro ejemplo, el operador de exponenciación tiene la particularidad de tener asociatividad a la derecha, a diferencia de los restantes operadores aritméticos que poseen asociatividad a la izquierda. Es interesante notar que, el order de evaluación siempre es de izquierda a derecha sin importar la asociatividad y la precedencia.

Código Salida
js
function echo(nombre, num) {
    console.log("Evaluando el lado " + nombre);
    return num;
}
// Nótese el operador división (/)
console.log(echo("izquierdo", 6) / echo("derecho", 2));
Evaluando el lado izquierdo
Evaluando el lado derecho
3
js
function echo(nombre, num) {
    console.log("Evaluando el lado " + nombre);
    return num;
}
// Nótese el operador potencia (**)
console.log(echo("izquierdo", 2) ** echo("derecho", 3));
Evaluando el lado izquierdo
Evaluando el lado derecho
8

La diferencia en asociatividad entra en juego cuando hay múltiples operadores con la misma precedencia. Con un único operador u operadores con diferente precedencia, la asociatividad no afecta la salida, como puede verse en el ejemplo de arriba. En el ejemplo debajo, observe como la asociatividad afecta la salida cuando múltiples operadores idénticos son usados.

Código Saludo
js
function echo(nombre, num) {
    console.log("Evaluando el lado " + nombre);
    return num;
}
// Nótese el operador división (/)
console.log(echo("izquierdo", 6) / echo("medio", 2) / echo("derecho", 3));
Evaluando el lado izquierdo
Evaluando el lado medio
Evaluando el lado derecho
1
js
function echo(nombre, num) {
    console.log("Evaluando el lado " + nombre);
    return num;
}
// Nótese el operador potencia (**)
console.log(echo("izquierdo", 2) ** echo("medio", 3) ** echo("derecho", 2));
Evaluando el lado izquierdo
Evaluando el lado medio
Evaluando el lado derecho
512
js
function echo(nombre, num) {
    console.log("Evaluando el lado " + nombre);
    return num;
}
// Nótese los paréntesis alrededor de las potencias de la izquierda y el medio
console.log((echo("izquierdo", 2) ** echo("medio", 3)) ** echo("derecho", 2));
Evaluando el lado izquierdo
Evaluando el lado medio
Evaluando el lado derecho
64

Viendo los fragmentos de códigos de arriba, 6 / 2 / 3 es lo mismo que (6 / 2) / 3 porque la división es asociativa a la izquierda. La potencia, por otro lado, es asociativa a la derecha, entonces 2 ** 3 ** 2 es lo mismo que 2 ** (3 ** 2). Por lo tanto, hacer (2 ** 3) ** 2 cambia el orden y el resultado en el 64 que se ve en la tabla de arriba.

Recuerde que la precedencia viene antes de la asociatividad. Entonces, mezclando división y potencia, esta última precede a la división. Por ejemplo, 2 ** 3 / 3 ** 2 resulta en 0.8888888888888888 porque es lo mismo que hacer (2 ** 3) / (3 ** 2).

Nota sobre agrupamiento y operadores de cortocircuito

En la tabla debajo, Agrupamiento se lista con la mayor precedencia. Sin embargo, esto no siempre significa que la expresión dentro de los símbolos de agrupación ( … ) es evaluada primero, especialmente cuando se trata de cortocircuitos.

Cortocircuitar es una jerga para la evaluación condicional. Por ejemplo, en la expresión a && (b + c), si a es falsy (en-US), entonces la expresión (b + c) no será evaluada, incluso si está dentro de paréntesis. Se podría decir que el operador de conjunción lógica ("&&") está "cortocircuitado". Junto con la conjunción lógica, otros operadores cortocircuitados son la disyunción lógica ("||"), la coalescencia nula ("??"), el encadenamiento opcional ("?."), y el operador condicional ternario. A continuación, algunos ejemplos.

js
a || (b * c); // evalúa primero `a`, luego produce `a` si `a` es "truthy"
a && (b < c); // evalúa primero `a`, luego produce `a` si `a` es "falsy"
a ?? (b || c); // evalúa primero `a`, luego produce `a` si `a` no es `null` ni `undefined`
a?.b.c; // evalúa primero `a`, luego produce `undefined` si `a` es `null` ó `undefined`

Ejemplos

js
3 > 2 && 2 > 1;
// Retorna `true`

3 > 2 > 1;
// Retorna `false` porque 3 > 2 es `true`, luego `true` es convertido a 1
// por coerción de tipos, luego `true` > 1 se convierte en 1 > 1, que es
// `false`. Agregar paréntesis hace que las cosas se vean claras: (3 > 2) > 1.

Tabla

La siguiente tabla lista los operadores en orden de mayor precedencia (19) a menor precedencia (1).

Nótese que la sintaxis spread está intencionalmente excluída de la tabla — porque, citando una respuesta en Stack Overflow, "la sintaxis spread no es un operador y por lo tanto no tiene una precedencia. Es parte de la sintaxis de arreglos literales y llamadas a funciones (y objetos literales)."

Precedencia Tipo de operador Asociatividad Operadores individuales
19 Agrupamiento n/a ( … )
18 Acceso a propiedades (notación por punto) a la izquierda … . …
Acceso a propiedades (notación por corchetes) a la izquierda … [ … ]
new (con lista de argumentos) n/a new … ( … )
Llamada a función a la izquierda … ( … )
Encadenamiento opcional a la izquierda ?.
17 new (sin lista de argumentos) a la derecha new …
16 Incremento sufijo n/a … ++
Decremento sufijo … --
15 NOT lógico (!) (en-US) a la derecha ! …
NOT a nivel de bits (~) (en-US) ~ …
Suma unaria (+) + …
Negación unaria (-) - …
Incremento prefijo ++ …
Decremento prefijo -- …
typeof typeof …
void void …
delete delete …
await await …
14 Potenciación (**) a la derecha … ** …
13 Multiplicación (*) a la izquierda … * …
División (/) … / …
Resto (%) … % …
12 Adición (+) a la izquierda … + …
Sustracción (-) … - …
11 Desplazamiento de bits a la izquierda (<<) (en-US) a la izquierda … << …
Desplazamiento de bits a la derecha (>>) (en-US) … >> …
Desplazamiento de bits a la derecha sin signo (>>>) (en-US) … >>> …
10 Menor a (<) (en-US) a la izquierda … < …
Menor o igual a (<=) (en-US) … <= …
Mayor a (>) (en-US) … > …
Mayor o igual a (>=) (en-US) … >= …
in … in …
instanceof … instanceof …
9 Igualdad (==) a la izquierda … == …
Desigualdad (!=) (en-US) … != …
Igualdad estricta (===) … === …
Desigualdad estricta (!==) (en-US) … !== …
8 AND a nivel de bits (&) (en-US) a la izquierda … & …
7 XOR a nivel de bits (^) (en-US) a la izquierda … ^ …
6 OR a nivel de bits (|) (en-US) a la izquierda … | …
5 AND lógico (&&) a la izquierda … && …
4 OR lógico (||) a la izquierda … || …
Operador de coalescencia nula (??) (en-US) a la izquierda … ?? …
3 Operador condicional (ternario) a la derecha … ? … : …
2 Asignación a la derecha … = …
… += …
… -= …
… **= …
… *= …
… /= …
… %= …
… <<= …
… >>= …
… >>>= …
… &= …
… ^= …
… |= …
… &&= …
… ||= …
… ??= …
yield a la derecha yield …
yield* yield* …
1 Operador coma a la izquierda … , …