← Voltar na listagem

06 de março de 20249 min de leitura

Como usar operadores ternários, nullish e optional chaining no JavaScript

Aprenda a usar os operadores ternários, nullish e optional chaining para simplificar o código JavaScript e lidar com valores, condições e propriedades de forma mais eficiente.

O JavaScript é uma linguagem de programação que oferece diversas formas de escrever código de forma concisa, elegante e expressiva. Neste artigo, vamos aprender sobre três operadores que podem facilitar a nossa vida na hora de lidar com valores, condições e propriedades: os operadores ternários, nullish e optional chaining.

O que são operadores ternários?

Os operadores ternários são uma forma de escrever uma expressão condicional que retorna um valor dependendo de uma condição. A sintaxe é a seguinte:

condição ? valor1 : valor2

Onde:

  • condição é uma expressão que pode ser avaliada como verdadeira ou falsa
  • valor1 é o valor que será retornado se a condição for verdadeira
  • valor2 é o valor que será retornado se a condição for falsa

Por exemplo, suponha que temos uma variável idade que armazena a idade de uma pessoa. Podemos usar um operador ternário para atribuir uma mensagem à variável status dependendo da idade:

let idade = 18;
let status = idade >= 18 ? 'Maior de idade' : 'Menor de idade';
console.log(status); // Maior de idade

O operador ternário é equivalente a escrever um bloco if...else, mas de forma mais compacta e legível. Por exemplo, o código acima poderia ser escrito assim:

let idade = 18;
let status;
if (idade >= 18) {
  status = 'Maior de idade';
} else {
  status = 'Menor de idade';
}
console.log(status); // Maior de idade

Quais são as vantagens de usar operadores ternários?

Os operadores ternários podem trazer algumas vantagens para o nosso código, como:

  • Reduzir o número de linhas e caracteres
  • Melhorar a clareza e a intenção do código
  • Evitar o uso de variáveis desnecessárias ou repetidas
  • Facilitar a atribuição de valores a variáveis ou propriedades
  • Permitir o uso de expressões condicionais em locais onde não seria possível usar blocos if...else, como em parâmetros de funções, retornos de funções, templates strings, etc.

Por exemplo, podemos usar um operador ternário para definir o valor de um parâmetro de uma função de forma dinâmica, dependendo de uma condição:

function saudar(nome, hora) {
  let periodo = hora < 12 ? 'Bom dia' : 'Boa tarde';
  console.log(`${periodo}, ${nome}!`);
}

saudar('Ana', 10); // Bom dia, Ana!
saudar('Bruno', 14); // Boa tarde, Bruno!

O que é o operador nullish?

O operador nullish (??) é um operador lógico que retorna o seu operando da direita se o operando da esquerda for null ou undefined, e o operando da esquerda caso contrário. A sintaxe é a seguinte:

valor1 ?? valor2

Onde:

  • valor1 é o valor que será retornado se não for null ou undefined
  • valor2 é o valor que será retornado se valor1 for null ou undefined

Por exemplo, suponha que temos uma função que recebe um objeto com as propriedades nome e sobrenome de uma pessoa, e queremos retornar o nome completo da pessoa. Podemos usar o operador nullish para definir um valor padrão para as propriedades que podem ser null ou undefined, como por exemplo, uma string vazia:

function nomeCompleto(pessoa) {
  let nome = pessoa.nome ?? '';
  let sobrenome = pessoa.sobrenome ?? '';
  return `${nome} ${sobrenome}`.trim();
}

console.log(nomeCompleto({ nome: 'Alice', sobrenome: 'Silva' })); // Alice Silva
console.log(nomeCompleto({ nome: 'Bob' })); // Bob
console.log(nomeCompleto({ sobrenome: 'Costa' })); // Costa
console.log(nomeCompleto({})); // (string vazia)

Qual é a diferença entre o operador nullish e o operador lógico OR (||)?

O operador lógico OR (||) é um operador que retorna o seu operando da direita se o operando da esquerda for um valor falso (false, 0, '', null, undefined ou NaN), e o operando da esquerda caso contrário. A sintaxe é a seguinte:

valor1 || valor2

O operador nullish é semelhante ao operador OR, mas tem uma diferença importante: ele só considera os valores null e undefined como falsos, e não os outros valores. Isso pode ser útil quando queremos definir um valor padrão para uma variável ou propriedade, mas não queremos ignorar os valores que podem ser válidos, mas que são falsos para o operador OR, como 0, '' ou false.

Por exemplo, suponha que temos uma função que recebe um objeto com as propriedades nome e ativo de um usuário, e queremos retornar uma mensagem de boas-vindas ou de despedida dependendo do status do usuário. Se usarmos o operador OR para definir um valor padrão para a propriedade ativo, podemos ter um problema, pois o valor false será ignorado e substituído pelo valor padrão, que é true. Veja:

function mensagem(usuario) {
  let nome = usuario.nome ?? 'Visitante';
  let ativo = usuario.ativo || true; // usando o operador OR
  return ativo ? `Olá, ${nome}!` : `Até logo, ${nome}!`;
}

console.log(mensagem({ nome: 'Carlos', ativo: true })); // Olá, Carlos!
console.log(mensagem({ nome: 'Daniela', ativo: false })); // Olá, Daniela! (errado, deveria ser Até logo, Daniela!)
console.log(mensagem({ nome: 'Eduardo' })); // Olá, Eduardo!
console.log(mensagem({ ativo: false })); // Olá, Visitante! (errado, deveria ser Até logo, Visitante!)
console.log(mensagem({})); // Olá, Visitante!

Para resolver esse problema, podemos usar o operador nullish, que vai respeitar o valor false e só vai usar o valor padrão se a propriedade for null ou undefined. Veja:

function mensagem(usuario) {
  let nome = usuario.nome ?? 'Visitante';
  let ativo = usuario.ativo ?? true; // usando o operador nullish
  return ativo ? `Olá, ${nome}!` : `Até logo, ${nome}!`;
}

console.log(mensagem({ nome: 'Carlos', ativo: true })); // Olá, Carlos!
console.log(mensagem({ nome: 'Daniela', ativo: false })); // Até logo, Daniela! (correto)
console.log(mensagem({ nome: 'Eduardo' })); // Olá, Eduardo!
console.log(mensagem({ ativo: false })); // Até logo, Visitante! (correto)
console.log(mensagem({})); // Olá, Visitante!

O que é o operador optional chaining?

O operador optional chaining (?.) é um operador que permite acessar as propriedades de um objeto que podem ser null ou undefined, sem gerar um erro. A sintaxe é a seguinte:

objeto?.propriedade

Onde:

  • objeto é o objeto que queremos acessar
  • propriedade é a propriedade que queremos acessar

Se o objeto for null ou undefined, o operador optional chaining vai retornar undefined, em vez de lançar um erro do tipo TypeError. Se o objeto não for null ou undefined, o operador optional chaining vai funcionar como o operador de acesso à propriedade (.).

Por exemplo, suponha que temos uma função que recebe um objeto com as propriedades nome, email e telefone de um cliente, e queremos retornar o contato preferido do cliente. Se usarmos o operContinuando o artigo:

ador optional chaining, podemos ter um problema, pois se o objeto for null ou undefined, vamos receber um erro do tipo TypeError: Cannot read property 'propriedade' of null (or undefined). Veja:

function contatoPreferido(cliente) {
  let nome = cliente.nome ?? 'Cliente';
  let email = cliente.email;
  let telefone = cliente.telefone;
  if (email) {
    return `O contato preferido de ${nome} é o email: ${email}`;
  } else if (telefone) {
    return `O contato preferido de ${nome} é o telefone: ${telefone}`;
  } else {
    return `Não temos o contato de ${nome}`;
  }
}

console.log(contatoPreferido({ nome: 'Fernanda', email: 'fernanda@gmail.com', telefone: '(11) 99999-9999' })); // O contato preferido de Fernanda é o email: fernanda@gmail.com
console.log(contatoPreferido({ nome: 'Gabriel', telefone: '(11) 88888-8888' })); // O contato preferido de Gabriel é o telefone: (11) 88888-8888
console.log(contatoPreferido({ nome: 'Helena' })); // Não temos o contato de Helena
console.log(contatoPreferido(null)); // TypeError: Cannot read property 'nome' of null

Para resolver esse problema, podemos usar o operador optional chaining, que vai evitar o erro e retornar undefined se o objeto for null ou undefined. Veja:

function contatoPreferido(cliente) {
  let nome = cliente?.nome ?? 'Cliente';
  let email = cliente?.email;
  let telefone = cliente?.telefone;
  if (email) {
    return `O contato preferido de ${nome} é o email: ${email}`;
  } else if (telefone) {
    return `O contato preferido de ${nome} é o telefone: ${telefone}`;
  } else {
    return `Não temos o contato de ${nome}`;
  }
}

console.log(contatoPreferido({ nome: 'Fernanda', email: 'fernanda@gmail.com', telefone: '(11) 99999-9999' })); // O contato preferido de Fernanda é o email: fernanda@gmail.com
console.log(contatoPreferido({ nome: 'Gabriel', telefone: '(11) 88888-8888' })); // O contato preferido de Gabriel é o telefone: (11) 88888-8888
console.log(contatoPreferido({ nome: 'Helena' })); // Não temos o contato de Helena
console.log(contatoPreferido(null)); // Não temos o contato de Cliente

Como usar o operador optional chaining com arrays e funções?

O operador optional chaining também pode ser usado para acessar os elementos de um array ou chamar uma função que podem ser null ou undefined, sem gerar um erro. A sintaxe é a seguinte:

array?.[indice]
funcao?.(argumentos)

Onde:

  • array é o array que queremos acessar
  • indice é o índice do elemento que queremos acessar
  • funcao é a função que queremos chamar
  • argumentos são os argumentos que queremos passar para a função

Se o array ou a função forem null ou undefined, o operador optional chaining vai retornar undefined, em vez de lançar um erro do tipo TypeError. Se o array ou a função não forem null ou undefined, o operador optional chaining vai funcionar como o operador de acesso ao elemento ([]) ou o operador de chamada de função (()).

Por exemplo, suponha que temos uma função que recebe um array de números e uma função de callback, e queremos aplicar a função de callback a cada elemento do array e retornar um novo array com os resultados. Podemos usar o operador optional chaining para evitar um erro se o array ou a função de callback forem null ou undefined. Veja:

function mapear(array, callback) {
  let resultado = [];
  for (let i = 0; i < array?.length; i++) {
    let elemento = array?.[i];
    let novoElemento = callback?.(elemento);
    resultado.push(novoElemento);
  }
  return resultado;
}

console.log(mapear([1, 2, 3], x => x * 2)); // [2, 4, 6]
console.log(mapear(null, x => x * 2)); // []
console.log(mapear([1, 2, 3], null)); // [undefined, undefined, undefined]
console.log(mapear(null, null)); // []

Conclusão

Neste artigo, aprendemos sobre três operadores que podem nos ajudar a escrever código mais conciso, elegante e expressivo no JavaScript: os operadores ternários, nullish e optional chaining. Vimos como eles funcionam, quais são as suas vantagens e como usá-los em diferentes situações. Esperamos que você tenha gostado e que possa aplicar esses conhecimentos nos seus projetos.