Conocemos a muchos operadores de la escuela. Son cosas como suma +
, multiplicación *
, resta -
, etc.
En este capítulo, comenzaremos con operadores simples y luego nos concentraremos en aspectos específicos de JavaScript, no cubiertos por la aritmética escolar.
Antes de continuar, comprendamos alguna terminología común.
Un operando : es a lo que se aplican los operadores. Por ejemplo, en la multiplicación de 5 * 2
hay dos operandos: el operando izquierdo es 5
y el operando derecho es 2
. A veces, la gente los llama "argumentos" en lugar de "operandos".
Un operador es unario si tiene un único operando. Por ejemplo, la negación unaria -
el signo de un número:
sea x = 1; x = -x; alerta( x ); // -1, se aplicó la negación unaria
Un operador es binario si tiene dos operandos. El mismo signo negativo también existe en forma binaria:
sea x = 1, y = 3; alerta( y - x ); // 2, binario menos resta valores
Formalmente, en los ejemplos anteriores tenemos dos operadores diferentes que comparten el mismo símbolo: el operador de negación, un operador unario que invierte el signo, y el operador de resta, un operador binario que resta un número de otro.
Se admiten las siguientes operaciones matemáticas:
Suma +
,
Resta -
,
Multiplicación *
,
División /
,
Resto %
,
Exponenciación **
.
Los primeros cuatro son sencillos, mientras que %
y **
necesitan algunas palabras sobre ellos.
El resto del operador %
, a pesar de su apariencia, no está relacionado con porcentajes.
El resultado de a % b
es el resto de la división entera de a
por b
.
Por ejemplo:
alerta (5 % 2); // 1, el resto de 5 dividido por 2 alerta (8% 3); // 2, el resto de 8 dividido por 3 alerta (8% 4); // 0, el resto de 8 dividido por 4
El operador de exponenciación a ** b
eleva a
a la potencia de b
.
En matemáticas escolares, lo escribimos como a b .
Por ejemplo:
alerta( 2 ** 2 ); // 2² = 4 alerta( 2 ** 3 ); // 2³ = 8 alerta (2 ** 4); // 2⁴ = 16
Al igual que en matemáticas, el operador de exponenciación también se define para números no enteros.
Por ejemplo, una raíz cuadrada es una exponenciación por ½:
alerta( 4 ** (1/2) ); // 2 (la potencia de 1/2 es lo mismo que una raíz cuadrada) alerta( 8 ** (1/3) ); // 2 (la potencia de 1/3 es lo mismo que una raíz cúbica)
Conozcamos las características de los operadores de JavaScript que van más allá de la aritmética escolar.
Por lo general, el operador más +
suma números.
Pero, si el binario +
se aplica a cadenas, las fusiona (concatena):
let s = "mi" + "cadena"; alerta(s); // mi cadena
Tenga en cuenta que si alguno de los operandos es una cadena, el otro también se convierte en una cadena.
Por ejemplo:
alerta ('1' + 2); // "12" alerta (2 + '1'); // "21"
Mira, no importa si el primer operando es una cadena o el segundo.
Aquí hay un ejemplo más complejo:
alerta(2 + 2 + '1'); // "41" y no "221"
Aquí los operadores trabajan uno tras otro. El primero +
suma dos números, por lo que devuelve 4
, luego el siguiente +
le agrega la cadena 1
, por lo que es como 4 + '1' = '41'
.
alerta('1' + 2 + 2); // "122" y no "14"
Aquí, el primer operando es una cadena, el compilador trata los otros dos operandos también como cadenas. El 2
se concatena con '1'
, por lo que es como '1' + 2 = "12"
y "12" + 2 = "122"
.
El binario +
es el único operador que admite cadenas de esa manera. Otros operadores aritméticos trabajan sólo con números y siempre convierten sus operandos en números.
Aquí está la demostración de resta y división:
alerta (6 - '2'); // 4, convierte '2' en un número alerta('6'/'2'); // 3, convierte ambos operandos a números
El plus +
existe en dos formas: la forma binaria que usamos anteriormente y la forma unaria.
El signo unario más o, en otras palabras, el operador más +
aplicado a un solo valor, no hace nada con los números. Pero si el operando no es un número, el signo unario más lo convierte en un número.
Por ejemplo:
// Sin efecto en los números sea x = 1; alerta( +x ); // 1 sea y = -2; alerta( +y ); // -2 // Convierte no números alerta (+verdadero); // 1 alerta(+"" ); // 0
En realidad, hace lo mismo que Number(...)
, pero es más corto.
La necesidad de convertir cadenas en números surge muy a menudo. Por ejemplo, si obtenemos valores de campos de formulario HTML, normalmente son cadenas. ¿Y si queremos sumarlos?
El plus binario los agregaría como cadenas:
let manzanas = "2"; let naranjas = "3"; alerta( manzanas + naranjas ); // "23", el binario más concatena cadenas
Si queremos tratarlos como números, debemos convertirlos y luego sumarlos:
let manzanas = "2"; let naranjas = "3"; // ambos valores convertidos a números antes del binario más alerta( +manzanas + +naranjas ); // 5 // la variante más larga // alerta( Número(manzanas) + Número(naranjas) ); // 5
Desde el punto de vista de un matemático, la abundancia de ventajas puede parecer extraña. Pero desde el punto de vista de un programador, no hay nada especial: primero se aplican los plus unarios, convierten cadenas en números y luego el plus binario los resume.
¿Por qué se aplican ventajas unarias a valores anteriores a los binarios? Como veremos, eso se debe a su mayor precedencia .
Si una expresión tiene más de un operador, el orden de ejecución se define por su precedencia o, en otras palabras, el orden de prioridad predeterminado de los operadores.
Desde el colegio todos sabemos que la multiplicación en la expresión 1 + 2 * 2
debe calcularse antes de la suma. Eso es exactamente lo que precede. Se dice que la multiplicación tiene mayor prioridad que la suma.
Los paréntesis anulan cualquier precedencia, por lo que si no estamos satisfechos con el orden predeterminado, podemos usarlos para cambiarlo. Por ejemplo, escribe (1 + 2) * 2
.
Hay muchos operadores en JavaScript. Cada operador tiene un número de precedencia correspondiente. El que tiene el número mayor se ejecuta primero. Si la precedencia es la misma, el orden de ejecución es de izquierda a derecha.
Aquí hay un extracto de la tabla de precedencia (no es necesario que lo recuerdes, pero ten en cuenta que los operadores unarios son mayores que los binarios correspondientes):
Precedencia | Nombre | Firmar |
---|---|---|
… | … | … |
14 | unario más | + |
14 | negación unaria | - |
13 | exponenciación | ** |
12 | multiplicación | * |
12 | división | / |
11 | suma | + |
11 | sustracción | - |
… | … | … |
2 | asignación | = |
… | … | … |
Como vemos, el “más unario” tiene una prioridad de 14
que es superior a la 11
de la “suma” (más binario). Por eso, en la expresión "+apples + +oranges"
, los más unarios funcionan antes que la suma.
Notemos que una asignación =
también es un operador. Aparece en la tabla de precedencia con la prioridad muy baja de 2
.
Por eso, cuando asignamos una variable, como x = 2 * 2 + 1
, primero se hacen los cálculos y luego se evalúa el =
, almacenando el resultado en x
.
sea x = 2 * 2 + 1; alerta( x ); // 5
El hecho de que =
sea un operador, no una construcción del lenguaje “mágico”, tiene una implicación interesante.
Todos los operadores en JavaScript devuelven un valor. Eso es obvio para +
y -
, pero también es cierto para =
.
La llamada x = value
escribe el value
en x
y luego lo devuelve .
Aquí hay una demostración que usa una tarea como parte de una expresión más compleja:
sea a = 1; sea b = 2; sea c = 3 - (a = b + 1); alerta( una ); // 3 alerta( c ); // 0
En el ejemplo anterior, el resultado de la expresión (a = b + 1)
es el valor asignado a a
(es decir, 3
). Luego se utiliza para evaluaciones posteriores.
Código curioso, ¿no? Debemos entender cómo funciona, porque a veces lo vemos en bibliotecas de JavaScript.
Aunque no escribas el código de esa manera. Estos trucos definitivamente no hacen que el código sea más claro ni legible.
Otra característica interesante es la posibilidad de encadenar tareas:
sean a, b, c; a = b = c = 2 + 2; alerta( una ); // 4 alerta (b); // 4 alerta( c ); // 4
Las tareas encadenadas se evalúan de derecha a izquierda. Primero, se evalúa la expresión más a la derecha 2 + 2
y luego se asigna a las variables de la izquierda: c
, b
y a
. Al final, todas las variables comparten un único valor.
Una vez más, por motivos de legibilidad, es mejor dividir dicho código en unas pocas líneas:
c = 2 + 2; segundo = c; a = c;
Esto es más fácil de leer, especialmente cuando se escanea rápidamente el código.
A menudo necesitamos aplicar un operador a una variable y almacenar el nuevo resultado en esa misma variable.
Por ejemplo:
sea n = 2; norte = norte + 5; norte = norte * 2;
Esta notación se puede acortar usando los operadores +=
y *=
:
sea n = 2; norte+= 5; // ahora n = 7 (igual que n = n + 5) norte *= 2; // ahora n = 14 (igual que n = n * 2) alerta( n ); // 14
Existen operadores cortos de “modificación y asignación” para todos los operadores aritméticos y bit a bit: /=
, -=
, etc.
Estos operadores tienen la misma prioridad que una asignación normal, por lo que se ejecutan después de la mayoría de los demás cálculos:
sea n = 2; norte *= 3 + 5; // parte derecha evaluada primero, igual que n *= 8 alerta( n ); // 16
Aumentar o disminuir un número en uno es una de las operaciones numéricas más comunes.
Entonces, existen operadores especiales para ello:
Incremento ++
aumenta una variable en 1:
deja contador = 2; contador++; // funciona igual que contador = contador + 1, pero es más corto alerta( contador ); // 3
Decremento --
disminuye una variable en 1:
dejar contador = 2; encimera--; // funciona igual que contador = contador - 1, pero es más corto alerta( contador ); // 1
Importante:
El incremento/disminución solo se puede aplicar a variables. Intentar usarlo en un valor como 5++
dará un error.
Los operadores ++
y --
se pueden colocar antes o después de una variable.
Cuando el operador busca la variable, está en “forma de sufijo”: counter++
.
La “forma de prefijo” es cuando el operador va antes de la variable: ++counter
.
Ambas declaraciones hacen lo mismo: aumentar counter
en 1
.
¿Hay alguna diferencia? Sí, pero solo podemos verlo si usamos el valor devuelto de ++/--
.
Aclaremos. Como sabemos, todos los operadores devuelven un valor. El incremento/disminución no es una excepción. La forma de prefijo devuelve el nuevo valor mientras que la forma de postfijo devuelve el valor anterior (antes del incremento/disminución).
Para ver la diferencia, aquí hay un ejemplo:
dejar contador = 1; let a = ++contador; // (*) alerta(a); // 2
En la línea (*)
, el prefijo ++counter
incrementa counter
y devuelve el nuevo valor, 2
. Entonces, la alert
muestra 2
.
Ahora, usemos la forma postfix:
dejar contador = 1; let a = contador++; // (*) cambiado ++contador a contador++ alerta(a); // 1
En la línea (*)
, la forma postfija counter++
también incrementa counter
pero devuelve el valor anterior (antes del incremento). Entonces, la alert
muestra 1
.
Para resumir:
Si no se utiliza el resultado del incremento/decremento, no hay diferencia en qué forma usar:
dejar contador = 0; contador++; ++contador; alerta( contador ); // 2, las líneas de arriba hicieron lo mismo
Si queremos aumentar un valor y usar inmediatamente el resultado del operador, necesitamos la forma de prefijo:
dejar contador = 0; alerta( ++contador ); // 1
Si queremos incrementar un valor pero usar su valor anterior, necesitamos el formato postfijo:
dejar contador = 0; alerta( contador++ ); // 0
Incremento/decremento entre otros operadores
Los operadores ++/--
también se pueden utilizar dentro de expresiones. Su precedencia es mayor que la de la mayoría de las otras operaciones aritméticas.
Por ejemplo:
dejar contador = 1; alerta (2 * ++ contador); // 4
Comparar con:
dejar contador = 1; alerta( 2 * contador++ ); // 2, porque contador++ devuelve el valor "antiguo"
Aunque técnicamente está bien, dicha notación suele hacer que el código sea menos legible. Una línea hace varias cosas, no es bueno.
Mientras se lee el código, un escaneo ocular rápido “vertical” puede fácilmente pasar por alto algo como counter++
y no será obvio que la variable aumentó.
Aconsejamos un estilo de “una línea – una acción”:
dejar contador = 1; alerta (2 * contador); contador++;
Los operadores bit a bit tratan los argumentos como números enteros de 32 bits y trabajan en el nivel de su representación binaria.
Estos operadores no son específicos de JavaScript. Son compatibles con la mayoría de los lenguajes de programación.
La lista de operadores:
Y ( &
)
O ( |
)
XOR ( ^
)
NO ( ~
)
MAYÚS IZQUIERDA ( <<
)
SHIFT A LA DERECHA ( >>
)
DESPLAZAMIENTO A LA DERECHA DE LLENADO CERO ( >>>
)
Estos operadores se utilizan muy raramente, cuando necesitamos jugar con números en el nivel más bajo (bit a bit). No necesitaremos estos operadores en el corto plazo, ya que el desarrollo web los utiliza poco, pero en algunas áreas especiales, como la criptografía, son útiles. Puede leer el capítulo Operadores bit a bit sobre MDN cuando surja la necesidad.
El operador de coma ,
uno de los operadores más raros e inusuales. A veces, se usa para escribir código más corto, por lo que necesitamos saberlo para entender qué está pasando.
El operador coma nos permite evaluar varias expresiones, dividiéndolas con una coma ,
. Se evalúa cada uno de ellos pero sólo se devuelve el resultado del último.
Por ejemplo:
sea a = (1 + 2, 3 + 4); alerta( una ); // 7 (el resultado de 3 + 4)
Aquí, se evalúa la primera expresión 1 + 2
y su resultado se descarta. Luego, se evalúa 3 + 4
y se devuelve como resultado.
La coma tiene una precedencia muy baja.
Tenga en cuenta que el operador de coma tiene una precedencia muy baja, inferior a =
, por lo que los paréntesis son importantes en el ejemplo anterior.
Sin ellos: a = 1 + 2, 3 + 4
evalúa +
primero, sumando los números en a = 3, 7
, luego el operador de asignación =
asigna a = 3
y el resto se ignora. Es como (a = 1 + 2), 3 + 4
.
¿Por qué necesitamos un operador que descarte todo excepto la última expresión?
A veces, la gente lo usa en construcciones más complejas para poner varias acciones en una línea.
Por ejemplo:
// tres operaciones en una línea para (a = 1, b = 3, c = a * b; a < 10; a++) { ... }
Estos trucos se utilizan en muchos marcos de JavaScript. Por eso los mencionamos. Pero normalmente no mejoran la legibilidad del código por lo que deberíamos pensarlo bien antes de usarlos.
importancia: 5
¿Cuáles son los valores finales de todas las variables a
, b
, c
y d
después del siguiente código?
sea a = 1, b = 1; sea c = ++a; // ? sea d = b++; // ?
La respuesta es:
a = 2
b = 2
c = 2
d = 1
sea a = 1, b = 1; alerta( ++a ); // 2, la forma de prefijo devuelve el nuevo valor alerta( b++ ); // 1, la forma postfix devuelve el valor anterior alerta( una ); // 2, incrementado una vez alerta (b); // 2, incrementado una vez
importancia: 3
x
a
del siguiente código?
sea a = 2; sea x = 1 + (a *= 2);
La respuesta es:
a = 4
(multiplicado por 2)
x = 5
(calculado como 1 + 4)
importancia: 5
¿Cuáles son los resultados de estas expresiones?
"" + 1 + 0 "" - 1 + 0 verdadero + falso 6 / "3" "2" * "3" 4 + 5 + "px" "$" + 4 + 5 "4" - 2 "4px" - 2 " -9 " + 5 " -9 " - 5 nulo + 1 indefinido + 1 " t n" - 2
Piensa bien, escribe y luego compara con la respuesta.
"" + 1 + 0 = "10" // (1) "" - 1 + 0 = -1 // (2) verdadero + falso = 1 6 / "3" = 2 "2" * "3" = 6 4 + 5 + "px" = "9px" "$" + 4 + 5 = "$45" "4" - 2 = 2 "4px" - 2 = NaN "-9" + 5 = "-9 5" // (3) " -9 " - 5 = -14 // (4) nulo + 1 = 1 // (5) indefinido + 1 = NaN // (6) " t n" - 2 = -2 // (7)
La suma con una cadena "" + 1
convierte 1
en una cadena: "" + 1 = "1"
, y luego tenemos "1" + 0
, se aplica la misma regla.
La -
(como la mayoría de las operaciones matemáticas) solo funciona con números, convierte una cadena vacía ""
en 0
.
La suma con una cadena agrega el número 5
a la cadena.
La resta siempre se convierte en números, por lo que hace que " -9 "
sea un número -9
(ignorando los espacios a su alrededor).
null
se convierte en 0
después de la conversión numérica.
undefined
se convierte en NaN
después de la conversión numérica.
Los caracteres de espacio se recortan del inicio y del final de la cadena cuando una cadena se convierte en un número. Aquí toda la cadena consta de caracteres de espacio, como t
, n
y un espacio "normal" entre ellos. Entonces, de manera similar a una cadena vacía, se convierte en 0
.
importancia: 5
Aquí hay un código que solicita al usuario dos números y muestra su suma.
Funciona incorrectamente. El resultado en el siguiente ejemplo es 12
(para valores de solicitud predeterminados).
¿Por qué? Arreglalo. El resultado debería ser 3
.
let a = Prompt("¿Primer número?", 1); let b = Prompt("¿Segundo número?", 2); alerta(a + b); // 12
La razón es que el mensaje devuelve la entrada del usuario como una cadena.
Entonces las variables tienen valores "1"
y "2"
respectivamente.
sea a = "1"; // indicador("¿Primer número?", 1); sea b = "2"; // indicador("¿Segundo número?", 2); alerta(a + b); // 12
Lo que debemos hacer es convertir cadenas en números antes de +
. Por ejemplo, usando Number()
o anteponiéndolos con +
.
Por ejemplo, justo antes prompt
:
let a = +prompt("¿Primer número?", 1); let b = +prompt("¿Segundo número?", 2); alerta(a + b); // 3
O en la alert
:
let a = Prompt("¿Primer número?", 1); let b = Prompt("¿Segundo número?", 2); alerta(+a + +b); // 3
Usando +
unario y binario en el código más reciente. Parece gracioso, ¿no?