Gabriel / Ramos

⟨ pintor de pixel ⟩

  • Blog
  • Relembrando operadores em JavaScript

Relembrando operadores em JavaScript

Reforçando conceitos chave, revisando alguns operadores e entendendo os mais "novos" introduzidos na linguagem

8 min. de leitura

Foto por runnyrem

Provavelmente você já ouviu falar (e talvez até já utilize, principalmente se você já mexeu com React, e suas renderizações condicionais) sobre os operadores ternário, "E" "OU" e como eles são avaliados.

Geralmente esses operadores fazem parte das primeiras coisas que aprendemos ao ter contato com lógica de programação. Entretanto, com algumas adições na linguagem (como o operador de coalescência nula), podemos aproveitar o momento para relembrar algumas coisas sobre o assunto.

Mas, antes de partirmos para os operadores, vamos aproveitar e falar sobre dois conceitos importantes da linguagem: coerção de tipos e valores truthy/falsy.

Coerção de tipos

Se olharmos o significado de coerção ou coagir, temos algo como reprimir ou forçar e coerção de tipo indica uma conversão de tipo que não é explicitamente indicada por quem desenvolve alguma operação e, por isso, "forçada".

É uma característica da linguagem e é principalmente aplicada quando falamos de valores booleanos e comparações. É exatamente o que ocorre, por exemplo, quando utilizamos == em comparações ao invés de ===.

console.log(1 == '1'); // retorna true

Operador == sofre coerção de tipos, ao avaliarmos a expressão acima o JavaScript converte os números para um tipo em comum o que não acontece com ===.

console.log(1 === '1'); // retorna false

É o mesmo que ocorre quando realizamos operações como:

console.log(1 + '1'); // retorna '11';

Nessa operação o JavaScript realizou uma conversão implícita dos valores para concatená-los, já que um era um número e outro era um string.

Esse conceito é necessário para que possamos entender os valores truthy e falsy e como esses valores funcionam em operações.

Valores truthy e falsy

Outra características da linguagem JavaScript, são valores que são interpretados (ou "avaliados") como verdadeiro/falso, mesmo não sendo especificamente booleanos.

Os valores falsy são: 0, false, string vazia '', null, undefined ou NaN.

Isso quer dizer que em contextos e operações tradicionalmente booleanas, como:

if (0 || false || '' || null || undefined || NaN) {
  console.log('falsy');
} else {
  console.log('truthy')
}

Esses valores são interpretados como falsos.

Com isso, podemos resumir que valores truthy são todos os outros que não são falsy, sejam eles números, strings, objetos, arrays ou qualquer outro.

Agora vamos aos operadores.


Operador ternário

Particularmente, acho que fica mais fácil de compreender o ternário se análisamos ele de duas formas diferentes: pensando em um "if reduzido" e fazendo uma comparação com funções "SE", no mundo das planilhas de Excel/Google Sheets.

Mas por quê um "if reduzido"?

Vamos pensar em uma situação bem comum, antes de aprender o operador ternário: precisamos mudar o valor de uma variável baseado em alguma condição, faríamos algo com if/else mais ou menos assim:

let minhaVariavel = 1;

if (minhaVariavel === 1) {
  minhaVariavel = 2;
}  else {
  minhaVariavel = 3;
}

E, no mundo das planilhas, vamos fazer o mesmo exemplo: se uma célula tiver o valor 1, mostraremos 2 em uma outra célula, se ela tiver qualquer outro valor, mostraremos 3. A seguir, tem uma tentativa (bem falha) de criar duas células de uma tabela aplicando a função "SE" na segunda célula.

| A |         B         |
|---|-------------------|
| 1 | =SE(A1 = 1; 2; 3) |

Em ambos os exemplos, estamos simplesmente alterando um valor baseado no valor inicial de alguma variável. Olhando mais afundo para a função "SE", podemos ver que ela segue uma certa estrutura:

SE(A1 = 1; 2; 3)

Podemos entender essa função como um bloco de informações separadas por ponto e vírgula (;). Vamos separar cada uma dessas, informações e entender o que elas fazem:

  • A = 1: realiza alguma verificação (se o valor da célula A é igual a 1);
  • 2: se a verificação anterior for verdadeira, exibe o valor 2;
  • 3: se a verificação for falsa, exibe 3.

Podemos agora dar um passo adiante e nomearmos esses "pedaços" de função. Dessa forma começamos a entender como o operador ternário funciona:

SE(verificação; valor se verdadeiro; valor se falso);

O operador ternário, segue exatamente esse mesmo modelo: realiza uma verificação, retorna um valor caso a verificação seja verdadeira ou retorna outro caso ela seja falsa.

Entretanto, o operador ternário não é separado por ponto e vírgula, ele segue a seguinte estrutura:

verificação ? valor se verdadeiro : valor se falso

No lugar do primeiro ponto e vírgula (logo após a verificação), uma interrogação é utilizada e logo depois o valor caso a operação seja verdadeira já é colocado. Por último, separamos com dois pontos (:) o valor a ser executado se a operação for verdadeira do valor falso.

Se aplicássemos isso no nosso exemplo de if/else anterior, teremos algo como:

let minhaVariavel = 1;
minhaVariavel = minhaVariavel === 1 ? 2 : 3;

Chegamos no mesmo resultado, mas com uma forma muito mais reduzida, não acha?

Vale lembrar que o ternário retorna os valores verdadeiros/falsos após a verificação.

No mundo React, é bem comum utilizar ternários para verificar e renderizar componentes baseado em algum dado:

const Component = () => (
    <>
    Qualquer coisa
    {verificacaoQualquer ? <ComponentCasoTrue /> : <ComponenteCasoFalse />}
  </>
);

Dessa forma, ComponentCasoTrue só será renderizado caso a verificacaoQualquer tenha um valor truthy, caso contrario o ComponentCasoFalse será exibido.

Operador "E" lógico

Muito comum utilizarmos o operador "E" ou "&&" em situações dentro de if/else, como:

let minhaVariavel = true;
let minhaVariavel2 = false;

if (minhaVariavel && minhaVariavel2) {
  console.log('faz algo se ambas as variáveis forem verdadeiras');
} else {
  console.log('faz algo se pelo menos alguma variável for falsa');
}

O que nem todo mundo sabe, é que esse operador também retorna determinado valor.

Esse operador retorna o operando do lado esquerdo, caso ele seja falsy e retorna o do lado direito caso ele seja truthy, em outras palavras, o que ocorre é isso aqui:

console.log(null && 'truthy'); // retorna null
console.log(undefined && 'truthy'); // retorna undefined
console.log(false && 'truthy'); // retorna false
console.log(0 && 'truthy'); // retorna 0
console.log('' && 'truthy'); // retorna ''
console.log(NaN && 'truthy'); // retorna ''

Assim como o ternário, também é outro operador muito utilizado em aplicações React:

const Component = () => (
  <>
    Qualquer coisa
    {verificacaoQualquer && <ComponentCasoTrue />}
  </>
);

Dessa forma, ComponentCasoTrue só será renderizado caso a verificacaoQualquer tenha um valor truthy.

Operador "OU" lógico

Bem parecido com o operador "E" lógico, o operador "OU" lógico é utilizado com os sinais de pipe ||.

Esse operador também retorna determinado operando, mas podemos pensar como se fosse o "inverso" do operador "E". Ou seja, retorna os operandos do lado direito caso os valores do lado esquerdo sejam falsy.

Com isso, temos algo como:

console.log(null || 'truthy'); // retorna 'truthy'
console.log(undefined || 'truthy'); // retorna 'truthy'
console.log(false || 'truthy'); // retorna 'truthy'
console.log(0 || 'truthy'); // retorna 'truthy'
console.log('' || 'truthy'); // retorna 'truthy'
console.log(NaN || 'truthy'); // retorna 'truthy'

Operador de coalescência nula (ou nullish coalescing)

Bem parecido com o operador "OU" lógico, o operador de coalescência nula é utilizado através de ?? também retorna um determinado operando.

Entretanto, ele retorna os operandos do lado direito somente se os valores do lado esquerdo forem null ou undefined. Valores como false, 0 ou '', serão retornados normalmente caso sejam os operandos do lado esquerdo.

Por isso ele é bem parecido com o operador "OU" lógico, apenas não leva em consideração todos os valores falsy.

Por fim, temos algo como:

console.log(null ?? 'truthy'); // retorna 'truthy'
console.log(undefined ?? 'truthy'); // retorna 'truthy'
console.log(false ?? 'truthy'); // retorna false
console.log(0 ?? 'truthy'); // retorna 0
console.log('' ?? 'truthy'); // retorna ''
console.log(NaN ?? 'truthy'); // retorna NaN

E o encadeamento opcional (ou optional chaining)?

Embora não seja um operador lógico, pode causar certa confusão já que, assim como o ternário e o operador de coalescência nula, o encadeamento opcional utiliza o sinal de ?.

Porém, ele é utilizado para acessar valores de objetos. Vamos pensar no seguinte objeto:

const pessoa = {
  nome: 'Gabriel',
  sobrenome: 'Ramos',
};

Caso tentássemos acessar algo inexistente no objeto, por exemplo pessoa.documents.cpf isso não existiria e teríamos um erro:

const pessoa = {
  nome: 'Gabriel',
  sobrenome: 'Ramos',
};

console.log(pessoa.documents.cpf); // Uncaught TypeError: Cannot read property 'cpf' of undefined

Esse operador serve justamente para que possamos, de certa forma, "validar" valores que podem ou não existir em objetos. Aplicamos esse operador ao acessar os valores de objetos: já fazíamos com . e agora podemos fazer com ?. ficando dessa forma:

const pessoa = {
  nome: 'Gabriel',
  sobrenome: 'Ramos',
  documents: null
};

console.log(pessoa.documents?.cpf); // undefined

Já ouviu falar em curto-circuito (ou short circuit)

Talvez você já tenha ouvido esse termo e, como estamos falando sobre esses operadores, vale a pena comentar o que ele quer dizer.

Esses operadores sofrem algo chamado curto-circuito. O que isso quer dizer é que, os valores dos operandos dos lados direito/esquerdo (justamente os que são retornados) não são nem executados (ou "avaliados"), caso não haja necessidade.

Ou seja, para esses operadores que vimos anteriormente, ao retornar determinada parte da operação, como, por exemplo no operador "OU" lógico:

console.log(false || 'ola'); // retorna olá
console.log(true || 'ola'); // retorna true

O lado direito da operação nem é executado caso não haja necessidade. Essa técnica pode ser interessante quando utilizamos esses operadores em blocos maiores de códigos ou funções, fazendo com que possamos executar ou não essas funções, por exemplo:

const valor = true;
const resultado = valor || executaAlgumaCoisa();

Caso valor seja verdadeiro, a função executaAlgumaCoisa não será nem executada. Ela só será executada caso seja false.

Em resumo, é isso que curto-circuito em operadores significa.

Combine e use esses operadores de forma livre

Você pode usar esses operadores da forma que mais for conveniente combinando em operações mais complexas e resolver como for necessário para seu caso.

Só lembre-se de usar todos eles de forma consistente e evitar deixar as operações complexas, afinal, é muito fácil criar diversas combinações com operações e dificultar o entendimento do código que está sendo escrito.


Compartilhe