(a==1 && a==2 && a==3) true? A Mágica do JavaScript

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: O problema que explodiu o Stack Overflow

\n\n

Imagine a situação: você está em uma entrevista, e o entrevistador, com um sorriso malicioso, pergunta: «A expressão a == 1 && a == 2 && a == 3 pode alguma vez retornar true?». A primeira reação é «Claro que não! Uma variável não pode ser igual a três números diferentes ao mesmo tempo».

\n\n

No entanto, se você conhece o JavaScript um pouco mais a fundo, sabe que nesta linguagem são possíveis as coisas mais inesperadas. Esta pergunta acumulou milhares de visualizações no Stack Overflow e se tornou um clássico para testar a compreensão de coerção de tipos, getters e wrappers de objetos em JS.

\n\n

Neste artigo, não apenas provaremos que isso é possível, mas também analisaremos 5 maneiras diferentes de fazer com que (a==1 && a==2 && a==3) retorne true. Você aprenderá como funciona a comparação não estrita (==), como ela difere da estrita (===) e como podemos manipulá-la.

\n\n

O artigo será útil tanto para iniciantes que desejam entender mais profundamente o JavaScript, quanto para desenvolvedores experientes que estão se preparando para uma entrevista. Vamos nessa!

\n\n

Método nº1: A mágica do valueOf (o mais popular)

\n\n

A maneira mais elegante e frequentemente citada é usar um objeto personalizado com o método valueOf sobrescrito. Em JavaScript, quando você compara um objeto com um primitivo usando ==, o motor automaticamente chama valueOf() (ou toString()) para converter o objeto em primitivo.

\n\n

Criaremos um objeto contador que, a cada chamada de valueOf, incrementa seu valor em 1.

\n\n
const a = {\n  value: 1,\n  valueOf() {\n    return this.value++;\n  }\n};\n\nconsole.log(a == 1 && a == 2 && a == 3); // true
\n\n

Como funciona:

\n
    \n
  • Na primeira comparação a == 1, valueOf() é chamado, retorna 1 e value é incrementado para 2.
  • \n
  • Na segunda comparação a == 2, valueOf() é chamado novamente, retorna 2 e value se torna 3.
  • \n
  • A terceira comparação a == 3 completa a cadeia com sucesso.
  • \n
\n\n

Este é um exemplo perfeito de type coercion (coerção forçada de tipos) em ação. É exatamente esse mecanismo que torna o JavaScript uma linguagem ao mesmo tempo flexível e perigosa.

\n\n

Método nº2: toString — o gêmeo do valueOf

\n\n

Se você sobrescrever toString em vez de valueOf, o resultado será o mesmo. O JavaScript na comparação não estrita pode usar qualquer um desses métodos para converter o objeto.

\n\n
const a = {\n  value: 1,\n  toString() {\n    return this.value++;\n  }\n};\n\nconsole.log(a == 1 && a == 2 && a == 3); // true
\n\n

A diferença é sutil: valueOf tem prioridade para comparações numéricas, enquanto toString tem para comparações de string. Mas no nosso caso, ambos funcionam perfeitamente.

\n\n

Método nº3: Getters no escopo global

\n\n

Muitos nem suspeitam que as variáveis globais em JavaScript são, na verdade, propriedades do objeto global (window no navegador, global no Node.js). E as propriedades podem ser definidas através de getters.

\n\n

Podemos definir um getter para a variável a diretamente no objeto global:

\n\n
let value = 1;\nObject.defineProperty(window, 'a', {\n  get() {\n    return value++;\n  }\n});\n\nconsole.log(a == 1 && a == 2 && a == 3); // true
\n\n

Este método é particularmente interessante porque a se comporta como uma variável comum, embora na verdade seja uma propriedade com getter. Cada vez que você acessa a, o getter retorna um novo valor.

\n\n

Blogs

Book Recommendations