Conhecemos muitos operadores da escola. São coisas como adição +
, multiplicação *
, subtração -
e assim por diante.
Neste capítulo, começaremos com operadores simples e depois nos concentraremos em aspectos específicos do JavaScript, não abordados pela aritmética escolar.
Antes de prosseguirmos, vamos entender alguma terminologia comum.
Um operando – é ao que os operadores são aplicados. Por exemplo, na multiplicação de 5 * 2
existem dois operandos: o operando esquerdo é 5
e o operando direito é 2
. Às vezes, as pessoas chamam isso de “argumentos” em vez de “operandos”.
Um operador é unário se tiver um único operando. Por exemplo, a negação unária -
inverte o sinal de um número:
seja x = 1; x = -x; alerta(x); // -1, a negação unária foi aplicada
Um operador é binário se tiver dois operandos. O mesmo sinal de menos também existe na forma binária:
seja x = 1, y = 3; alerta( y - x ); // 2, binário menos subtrai valores
Formalmente, nos exemplos acima temos dois operadores diferentes que compartilham o mesmo símbolo: o operador de negação, um operador unário que inverte o sinal, e o operador de subtração, um operador binário que subtrai um número de outro.
As seguintes operações matemáticas são suportadas:
Adição +
,
Subtração -
,
Multiplicação *
,
Divisão /
,
%
restante,
Exponenciação **
.
Os quatro primeiros são diretos, enquanto %
e **
precisam de algumas palavras sobre eles.
O operador restante %
, apesar de sua aparência, não está relacionado a porcentagens.
O resultado de a % b
é o restante da divisão inteira de a
por b
.
Por exemplo:
alerta( 5% 2 ); // 1, o resto de 5 dividido por 2 alerta(8% 3); // 2, o resto de 8 dividido por 3 alerta(8% 4); // 0, o resto de 8 dividido por 4
O operador de exponenciação a ** b
eleva a
à potência de b
.
Na matemática escolar, escrevemos isso como a b .
Por exemplo:
alerta(2 ** 2); //2² = 4 alerta(2 ** 3); //2³ = 8 alerta(2 ** 4); //2⁴ = 16
Assim como na matemática, o operador de exponenciação também é definido para números não inteiros.
Por exemplo, uma raiz quadrada é uma exponenciação por ½:
alerta( 4 ** (1/2) ); // 2 (a potência de 1/2 é igual à raiz quadrada) alerta( 8 ** (1/3) ); // 2 (a potência de 1/3 é igual a uma raiz cúbica)
Vamos conhecer os recursos dos operadores JavaScript que vão além da aritmética escolar.
Normalmente, o operador mais +
soma números.
Mas, se o binário +
for aplicado a strings, ele as mescla (concatena):
deixe s = "meu" + "string"; alerta(s); // minhastring
Observe que se algum dos operandos for uma string, o outro também será convertido em uma string.
Por exemplo:
alerta('1' + 2); // "12" alerta(2 + '1'); // "21"
Veja, não importa se o primeiro operando é uma string ou o segundo.
Aqui está um exemplo mais complexo:
alerta(2 + 2 + '1' ); // "41" e não "221"
Aqui, os operadores trabalham um após o outro. O primeiro +
soma dois números, então retorna 4
, então o próximo +
adiciona a string 1
a ele, então é como 4 + '1' = '41'
.
alerta('1' + 2 + 2); // "122" e não "14"
Aqui, o primeiro operando é uma string, o compilador trata os outros dois operandos também como strings. O 2
é concatenado com '1'
, então é como '1' + 2 = "12"
e "12" + 2 = "122"
.
O binário +
é o único operador que suporta strings dessa forma. Outros operadores aritméticos trabalham apenas com números e sempre convertem seus operandos em números.
Aqui está a demonstração para subtração e divisão:
alerta( 6 - '2' ); // 4, converte '2' em um número alerta('6'/'2'); // 3, converte ambos os operandos em números
O sinal de mais +
existe em duas formas: a forma binária que usamos acima e a forma unária.
O sinal de mais unário ou, em outras palavras, o operador de mais +
aplicado a um único valor, não faz nada com os números. Mas se o operando não for um número, o sinal de adição unário o converte em um número.
Por exemplo:
// Sem efeito nos números seja x = 1; alerta( +x); //1 seja y = -2; alerta( +y); // -2 // Converte não-números alerta( +verdadeiro); //1 alerta( +""); //0
Na verdade, faz a mesma coisa que Number(...)
, mas é mais curto.
A necessidade de converter strings em números surge com muita frequência. Por exemplo, se estivermos obtendo valores de campos de formulário HTML, eles geralmente são strings. E se quisermos somá-los?
O plus binário os adicionaria como strings:
deixe maçãs = "2"; deixe laranjas = "3"; alerta(maçãs + laranjas); // "23", o binário mais concatena strings
Se quisermos tratá-los como números, precisamos convertê-los e depois somá-los:
deixe maçãs = "2"; deixe laranjas = "3"; //ambos os valores convertidos em números antes do binário mais alerta( +maçãs + +laranjas ); //5 // a variante mais longa // alerta(Número(maçãs) + Número(laranjas)); //5
Do ponto de vista de um matemático, a abundância de vantagens pode parecer estranha. Mas do ponto de vista de um programador, não há nada de especial: os sinais de adição unários são aplicados primeiro, eles convertem strings em números e, em seguida, o sinal de adição binário os soma.
Por que vantagens unárias são aplicadas a valores anteriores aos binários? Como veremos, isso se deve à sua maior precedência .
Se uma expressão tiver mais de um operador, a ordem de execução é definida pela sua precedência , ou, em outras palavras, pela ordem de prioridade padrão dos operadores.
Da escola, todos sabemos que a multiplicação na expressão 1 + 2 * 2
deve ser calculada antes da adição. Essa é exatamente a questão da precedência. Diz-se que a multiplicação tem uma precedência maior que a adição.
Os parênteses substituem qualquer precedência, portanto, se não estivermos satisfeitos com a ordem padrão, podemos usá-los para alterá-la. Por exemplo, escreva (1 + 2) * 2
.
Existem muitos operadores em JavaScript. Cada operador possui um número de precedência correspondente. Aquele com o número maior é executado primeiro. Se a precedência for a mesma, a ordem de execução será da esquerda para a direita.
Aqui está um extrato da tabela de precedência (você não precisa se lembrar disso, mas observe que os operadores unários são superiores aos binários correspondentes):
Precedência | Nome | Sinal |
---|---|---|
… | … | … |
14 | unário mais | + |
14 | negação unária | - |
13 | exponenciação | ** |
12 | multiplicação | * |
12 | divisão | / |
11 | adição | + |
11 | subtração | - |
… | … | … |
2 | atribuição | = |
… | … | … |
Como podemos ver, o “mais unário” tem uma prioridade de 14
que é maior que o 11
da “adição” (mais binário). É por isso que, na expressão "+apples + +oranges"
, os sinais de adição unários funcionam antes da adição.
Observemos que uma atribuição =
também é um operador. Ele está listado na tabela de precedência com prioridade muito baixa de 2
.
É por isso que, quando atribuímos uma variável, como x = 2 * 2 + 1
, os cálculos são feitos primeiro e depois o =
é avaliado, armazenando o resultado em x
.
seja x = 2 * 2 + 1; alerta(x); //5
O fato de =
ser um operador, e não uma construção “mágica” de linguagem, tem uma implicação interessante.
Todos os operadores em JavaScript retornam um valor. Isso é óbvio para +
e -
, mas também é verdade para =
.
A chamada x = value
escreve o value
em x
e depois o retorna .
Aqui está uma demonstração que usa uma atribuição como parte de uma expressão mais complexa:
seja a = 1; seja b = 2; seja c = 3 - (a = b + 1); alerta(uma); //3 alerta( c ); //0
No exemplo acima, o resultado da expressão (a = b + 1)
é o valor que foi atribuído a a
(ou seja, 3
). Em seguida, é usado para avaliações adicionais.
Código engraçado, não é? Devemos entender como funciona, porque às vezes vemos isso em bibliotecas JavaScript.
Embora, por favor, não escreva o código assim. Esses truques definitivamente não tornam o código mais claro ou legível.
Outro recurso interessante é a capacidade de encadear atribuições:
seja a, b, c; uma = b = c = 2 + 2; alerta(uma); //4 alerta( b ); //4 alerta( c ); //4
As tarefas encadeadas são avaliadas da direita para a esquerda. Primeiro, a expressão mais à direita 2 + 2
é avaliada e depois atribuída às variáveis à esquerda: c
, b
e a
. No final, todas as variáveis compartilham um único valor.
Mais uma vez, para fins de legibilidade, é melhor dividir esse código em poucas linhas:
c = 2 + 2; b=c; uma=c;
Isso é mais fácil de ler, especialmente ao examinar rapidamente o código.
Freqüentemente precisamos aplicar um operador a uma variável e armazenar o novo resultado nessa mesma variável.
Por exemplo:
seja n = 2; n=n+5; n=n*2;
Esta notação pode ser abreviada usando os operadores +=
e *=
:
seja n = 2; n+= 5; // agora n = 7 (o mesmo que n = n + 5) n *= 2; // agora n = 14 (o mesmo que n = n * 2) alerta(n); // 14
Existem operadores curtos de “modificar e atribuir” para todos os operadores aritméticos e bit a bit: /=
, -=
, etc.
Esses operadores têm a mesma precedência que uma atribuição normal, portanto são executados após a maioria dos outros cálculos:
seja n = 2; n *= 3 + 5; // parte direita avaliada primeiro, igual a n *= 8 alerta(n); // 16
Aumentar ou diminuir um número em um está entre as operações numéricas mais comuns.
Portanto, existem operadores especiais para isso:
Increment ++
aumenta uma variável em 1:
deixe contador = 2; contador++; // funciona da mesma forma que contador = contador + 1, mas é mais curto alerta(contador); //3
Decrementar --
diminui uma variável em 1:
deixe contador = 2; contador--; // funciona da mesma forma que counter = counter - 1, mas é mais curto alerta(contador); //1
Importante:
O incremento/decremento só pode ser aplicado a variáveis. Tentar usá-lo em um valor como 5++
causará um erro.
Os operadores ++
e --
podem ser colocados antes ou depois de uma variável.
Quando o operador vai atrás da variável, ela está na “forma postfix”: counter++
.
A “forma de prefixo” é quando o operador vai antes da variável: ++counter
.
Ambas as declarações fazem a mesma coisa: aumentar counter
em 1
.
Existe alguma diferença? Sim, mas só podemos ver se usarmos o valor retornado de ++/--
.
Vamos esclarecer. Como sabemos, todos os operadores retornam um valor. Incremento/decremento não é exceção. O formulário prefixo retorna o novo valor enquanto o formulário pós-fixo retorna o valor antigo (antes do incremento/decremento).
Para ver a diferença, aqui está um exemplo:
deixe contador = 1; deixe a = ++contador; // (*) alerta(a); //2
Na linha (*)
, o prefixo ++counter
incrementa counter
e retorna o novo valor, 2
. Então, o alert
mostra 2
.
Agora, vamos usar a forma postfix:
deixe contador = 1; deixe a = contador++; // (*) alterado ++contador para contador++ alerta(a); //1
Na linha (*)
, o formulário postfix counter++
também incrementa counter
mas retorna o valor antigo (antes do incremento). Então, o alert
mostra 1
.
Para resumir:
Se o resultado do incremento/decremento não for usado, não há diferença em qual forma usar:
deixe contador = 0; contador++; ++contador; alerta(contador); // 2, as linhas acima fizeram o mesmo
Se quisermos aumentar um valor e usar imediatamente o resultado do operador, precisamos da forma de prefixo:
deixe contador = 0; alerta(++contador); //1
Se quisermos incrementar um valor, mas usar seu valor anterior, precisaremos do formato postfix:
deixe contador = 0; alerta(contador++); //0
Incremento/decremento entre outros operadores
Os operadores ++/--
também podem ser usados dentro de expressões. Sua precedência é maior que a maioria das outras operações aritméticas.
Por exemplo:
deixe contador = 1; alerta(2 * ++contador); //4
Compare com:
deixe contador = 1; alerta(2 * contador++); // 2, porque counter++ retorna o valor "antigo"
Embora tecnicamente aceitável, essa notação geralmente torna o código menos legível. Uma linha faz várias coisas – não é bom.
Ao ler o código, uma varredura ocular “vertical” rápida pode facilmente perder algo como counter++
e não será óbvio que a variável aumentou.
Aconselhamos um estilo de “uma linha – uma ação”:
deixe contador = 1; alerta(2 * contador); contador++;
Os operadores bit a bit tratam os argumentos como números inteiros de 32 bits e trabalham no nível de sua representação binária.
Esses operadores não são específicos do JavaScript. Eles são suportados na maioria das linguagens de programação.
A lista de operadores:
E ( &
)
OU ( |
)
XOR ( ^
)
NÃO ( ~
)
MUDANÇA ESQUERDA ( <<
)
MUDANÇA PARA A DIREITA ( >>
)
MUDANÇA À DIREITA DE PREENCHIMENTO ZERO ( >>>
)
Esses operadores são usados muito raramente, quando precisamos mexer com números no nível mais baixo (bit a bit). Não precisaremos desses operadores tão cedo, pois o desenvolvimento web faz pouco uso deles, mas em algumas áreas especiais, como criptografia, eles são úteis. Você pode ler o capítulo Operadores Bitwise sobre MDN quando surgir uma necessidade.
O operador ,
é um dos operadores mais raros e incomuns. Às vezes, é usado para escrever códigos mais curtos, então precisamos conhecê-lo para entender o que está acontecendo.
O operador vírgula permite avaliar diversas expressões, dividindo-as por vírgula ,
. Cada um deles é avaliado, mas apenas o resultado do último é retornado.
Por exemplo:
seja a = (1 + 2, 3 + 4); alerta(uma); // 7 (o resultado de 3 + 4)
Aqui, a primeira expressão 1 + 2
é avaliada e seu resultado é descartado. Então, 3 + 4
é avaliado e retornado como resultado.
A vírgula tem uma precedência muito baixa
Observe que o operador vírgula tem precedência muito baixa, menor que =
, portanto os parênteses são importantes no exemplo acima.
Sem eles: a = 1 + 2, 3 + 4
avalia +
primeiro, somando os números em a = 3, 7
, depois o operador de atribuição =
atribui a = 3
e o resto é ignorado. É como (a = 1 + 2), 3 + 4
.
Por que precisamos de um operador que jogue fora tudo, exceto a última expressão?
Às vezes, as pessoas usam isso em construções mais complexas para colocar várias ações em uma linha.
Por exemplo:
//três operações em uma linha para (a = 1, b = 3, c = a * b; a < 10; a++) { ... }
Esses truques são usados em muitas estruturas JavaScript. É por isso que os estamos mencionando. Mas geralmente eles não melhoram a legibilidade do código, então devemos pensar bem antes de usá-los.
importância: 5
Quais são os valores finais de todas as variáveis a
, b
, c
e d
após o código abaixo?
seja a = 1, b = 1; seja c = ++a; // ? seja d = b++; // ?
A resposta é:
a = 2
b = 2
c = 2
d = 1
seja a = 1, b = 1; alerta(++a); // 2, o formato do prefixo retorna o novo valor alerta(b++); // 1, o formulário postfix retorna o valor antigo alerta(uma); // 2, incrementado uma vez alerta( b ); // 2, incrementado uma vez
importância: 3
Quais são os valores de a
e x
após o código abaixo?
seja a = 2; seja x = 1 + (uma *= 2);
A resposta é:
a = 4
(multiplicado por 2)
x = 5
(calculado como 1 + 4)
importância: 5
Quais são os resultados dessas expressões?
"" + 1 + 0 "" - 1 + 0 verdadeiro + falso 6 / "3" "2" * "3" 4 + 5 + "px" "$" + 4 + 5 "4" - 2 "4px" - 2 "-9" + 5 " -9 " - 5 nulo + 1 indefinido + 1 "tn" - 2
Pense bem, anote e compare com a resposta.
"" + 1 + 0 = "10" // (1) "" - 1 + 0 = -1 // (2) verdadeiro + 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) "tn" - 2 = -2 // (7)
A adição com uma string "" + 1
converte 1
em uma string: "" + 1 = "1"
, e então temos "1" + 0
, a mesma regra é aplicada.
A subtração -
(como a maioria das operações matemáticas) só funciona com números, converte uma string vazia ""
em 0
.
A adição com uma string anexa o número 5
à string.
A subtração sempre é convertida em números, portanto torna " -9 "
um número -9
(ignorando os espaços ao seu redor).
null
se torna 0
após a conversão numérica.
undefined
torna-se NaN
após a conversão numérica.
Os caracteres de espaço são cortados no início e no fim da string quando uma string é convertida em um número. Aqui, toda a string consiste em caracteres de espaço, como t
, n
e um espaço “regular” entre eles. Então, da mesma forma que uma string vazia, ela se torna 0
.
importância: 5
Aqui está um código que pede dois números ao usuário e mostra sua soma.
Funciona incorretamente. A saída no exemplo abaixo é 12
(para valores de prompt padrão).
Por que? Corrija isso. O resultado deve ser 3
.
deixe a = prompt("Primeiro número?", 1); deixe b = prompt("Segundo número?", 2); alerta(a + b); //12
O motivo é que o prompt retorna a entrada do usuário como uma string.
Portanto, as variáveis têm valores "1"
e "2"
, respectivamente.
deixe a = "1"; // prompt("Primeiro número?", 1); seja b = "2"; // prompt("Segundo número?", 2); alerta(a + b); //12
O que devemos fazer é converter strings em números antes de +
. Por exemplo, usando Number()
ou acrescentando +
.
Por exemplo, logo antes de prompt
:
deixe a = +prompt("Primeiro número?", 1); deixe b = +prompt("Segundo número?", 2); alerta(a + b); //3
Ou no alert
:
deixe a = prompt("Primeiro número?", 1); deixe b = prompt("Segundo número?", 2); alerta(+a + +b); //3
Usando unário e binário +
no código mais recente. Parece engraçado, não é?