O que é reflexão e introspecção em JavaScript e por que você precisa disso?
\n\nImagine que você é um programador-detetive. Você tem um objeto, mas não sabe o que há dentro dele. Quais são suas propriedades? Qual é a sua natureza — array, função ou apenas um conjunto de dados? Na vida normal, apenas olhamos para o código, mas no mundo dinâmico do JavaScript, seu programa precisa ser capaz de fazer isso sozinho. Isso é reflexão e introspecção.
\n\nEsses termos soam como filosofia, mas na verdade são ferramentas poderosas. Introspecção é quando o código olha para si mesmo: verifica o tipo de uma variável, descobre o nome de uma função ou lista as propriedades de um objeto. Reflexão vai além — é a capacidade do código de se modificar durante a execução: adicionar novos métodos, alterar protótipos ou até mesmo criar objetos proxy.
\n\nÀ primeira vista, pode parecer que isso é necessário apenas para autores de frameworks complexos. Mas, na verdade, todos os dias você usa introspecção, mesmo sem perceber. Quando você escreve typeof x === 'string' — você já está praticando introspecção. E quando usa Object.assign para copiar propriedades — está aplicando reflexão.
Neste artigo, vamos abordar todos os métodos e técnicas principais. Você aprenderá como "olhar para dentro" de qualquer objeto, como trabalhar com dados desconhecidos de forma segura e como escrever código mais flexível e adaptável. Vamos lá!
\n\nFundamentos da introspecção: vendo o que temos em mãos
\n\nA introspecção começa com uma pergunta simples: "O que é isso?". Em JavaScript, existem vários operadores e métodos embutidos que ajudam a responder essa pergunta.
\n\nOperador typeof: verificação rápida de tipo
\n\nEste é seu primeiro ajudante. typeof retorna uma string indicando o tipo do operando. É simples, mas tem algumas armadilhas.
console.log(typeof 42); // "number"\nconsole.log(typeof 'hello'); // "string"\nconsole.log(typeof true); // "boolean"\nconsole.log(typeof undefined); // "undefined"\nconsole.log(typeof null); // "object" — aqui está o famoso bug!\nconsole.log(typeof []); // "object" — e isso não é um bug, é uma característica\nconsole.log(typeof function(){}); // "function"\n\nObserve: typeof null retorna "object". Este é um erro histórico do JavaScript que não será corrigido. typeof [] também retorna "object", o que é lógico, pois um array é um subtipo de objeto. Mas como então diferenciar um array de um objeto comum? Para isso, existem outras ferramentas.
Dica útil: typeof é ideal para verificar se uma variável está definida, sem o risco de lançar uma exceção ReferenceError.
if (typeof someGlobalVar !== 'undefined') {\n // Usa someGlobalVar com segurança\n}\n\ninstanceof: verificação da cadeia de protótipos
\n\nSe typeof responde à pergunta "qual é o tipo primitivo?", então instanceof responde a "é um objeto de uma determinada classe?". Ele verifica se o protótipo do construtor está presente na cadeia de protótipos do objeto.
const arr = [1, 2, 3];\nconsole.log(arr instanceof Array); // true\nconsole.log(arr instanceof Object); // true — porque Array herda de Object\n\nconst date = new Date();\nconsole.log(date instanceof Date); // true\nconsole.log(date instanceof Object); // true\n\n// Mas com primitivos não funciona\nconsole.log('hello' instanceof String); // false — primitivo não é objeto\n\nUma nuance importante: instanceof pode falhar ao trabalhar com iframes ou diferentes contextos de execução (por exemplo, no Node.js). Cada contexto tem seu próprio objeto global, e [] instanceof window.Array pode retornar false se o array foi criado em outro frame. Para esses casos, é melhor usar Array.isArray().