Guia Completo de Conceitos Essenciais de JavaScript para Entrevistas Técnicas

  1. Formas de Carregamento Assíncrono de Scripts em JavaScript

Quando o navegador encontra uma tag <script> no HTML, ele pausa a análise e renderização da página para baixar e executar o script. Múltiplos scripts são baixados em paralelo, mas executados na ordem em que aparecem no documento.

Método com atributo defer

Ao adicionar defer à tag script:

  • O download e a execução não bloqueiam a análise e renderização da página
  • Múltiplos scripts defer são baixados em paralelo, mas executados sequencialmente
  • A execução ocorre após a conclusão da análise do DOM, antes do evento DOMContentLoaded

Método com atributo async

Ao adicionar async à tag script:

  • O download não bloqueia a análise, mas a execução bloqueia a renderização
  • O primeiro script a ser totalmente baixado será executado imediatamente, sem respeitar a ordem do documento
  • O impacto no evento DOMContentLoaded é mínimo, pois o tempo de execução geralmente é curto

Criação dinâmica de elementos script

Antes de existirem defer e async, a técnica consistia em criar dinamicamente elementos <script> e inseri-los no DOM após o carregamento completo da página usando window.onload.

  1. Diferenças entre var, let e const

  • Elevação de declaração (hoisting): var possui hoisting; let e const não apresentam elevação de declaração
  • Re-declaração: Variáveis com var podem ser redeclaradas; let e const não permitem re-declaração
  • Escopo de bloco: var não possui escopo de bloco; let e const possuem escopo de bloco
  • Inicialização obrigatória: const exige inicialização na declaração
  • Mutabilidade: const não permite reatribuição; var e let permitem
  • Zona morta temporal (TDZ): let e const ficam indisponíveis antes da declaração
  • Propriedade global: var declara variáveis como propriedades de window; let e const não
console.log(valorX) // undefined
console.log(valorY) // ReferenceError
var valorX = 10;
let valorY = 20;
  1. Tipos de Dados em JavaScript

Tipos Primitivos

  • String: Ao concatenar com qualquer outro tipo, o resultado é uma string
  • Number: Utiliza representação de ponto flutuante de 64 bits. NaN é do tipo number mas não representa um número válido. isNaN() verifica se o valor é NaN
  • Boolean: Pode assumir apenas true ou false
  • Undefined: Indica variável declarada mas não inicializada
  • Null: Representa ausência intencional de valor. typeof null retorna "object"
  • Symbol: Cria valores únicos, útil para evitar conflitos de propriedades em objetos
  • BigInt: Permite representar números inteiros com precisão arbitrária além do limite de Number

Tipos de Referência (Objetos)

  • Object, Array, Function, RegExp, Date
  1. Valores Retornados pelo typeof

O operador typeof pode retornar: "number", "string", "boolean", "undefined", "object", "function", "symbol", "bigint".

  1. Diferença entre null e undefined

  • null representa a ausência intencional de um objeto; convertido para número resulta em 0; typeof retorna "object"
  • undefined representa uma variável não definida; convertido para número resulta em NaN; typeof retorna "undefined"
  • null == undefined é true, mas null === undefined é false
  1. Diferença entre == e ===

== (igualdade simples): Realiza conversão implícita de tipos antes da comparação. Strings são convertidas para números, booleanos para 0 ou 1, e objetos invocam valueOf() e toString().

1 == '1'        // true
0 == false      // true
[] == false     // true
null == undefined // true

=== (igualdade estrita): Compara tanto tipo quanto valor. Se os tipos diferem, retorna false imediatamente.

0 === '0'         // false
0 === false       // false
null === undefined // false
  1. Diferença entre typeof e instanceof

  • typeof retorna uma string com o tipo do dado
  • instanceof retorna um booleano indicando se o objeto é instância de um construtor específico
  • typeof não diferencia tipos de objetos; instanceof pode verificar tipos específicos
  1. Implementação Manual do instanceof

O operador instanceof verifica se o prototype do construtor está presente na cadeia de protótipos do objeto:

function verificarInstancia(objeto, construtor) {
  if (objeto === null || typeof objeto !== 'object') {
    return false;
  }
  if (typeof construtor !== 'function') {
    return false;
  }
  let prototipoAtual = Object.getPrototypeOf(objeto);
  while (prototipoAtual !== null) {
    if (prototipoAtual === construtor.prototype) {
      return true;
    }
    prototipoAtual = Object.getPrototypeOf(prototipoAtual);
  }
  return false;
}
  1. Diferença entre substring e substr

const texto = "hello, world!";
console.log(texto.substring(7, 12));  // "world"
console.log(texto.substr(7, 5));      // "world"

substring(inicio, fim) utiliza índices de início e fim. substr(inicio, comprimento) utiliza índice inicial e quantidade de caracteres.

  1. Diferença entre for...in e for...of

Aspecto for...in for...of
Retorna Chaves (keys) Valores (values)
Adequado para Objetos, arrays, strings Iteráveis: Array, String, Map, Set, Generator
Propriedades do protótipo Sim, percorre propriedades herdadas Não, apenas propriedades próprias
Ordem garantida Não Sim

Para iterar sobre objetos com for...of:

const pessoa = { nome: "Ana", idade: 30, cidade: "Lisboa" };

pessoa[Symbol.iterator] = function* () {
  const chaves = Object.keys(this);
  for (const chave of chaves) {
    yield this[chave];
  }
};

for (const valor of pessoa) {
  console.log(valor); // "Ana", 30, "Lisboa"
}
  1. Compreensão do AJAX e Implementação

AJAX (Asynchronous JavaScript and XML) permite comunicação assíncrona com servidores. O objeto XMLHttpRequest possui 5 estados:

  • 0 - Não inicializado
  • 1 - Conexão estabelecida, requisição enviada
  • 2 - Requisição recebida pelo servidor
  • 3 - Processando resposta
  • 4 - Resposta completa
  1. Comparação: AJAX, Axios e Fetch

  • AJAX: Baseado em XMLHttpRequest, propenso a callback hell, código verboso
  • Fetch: API nativa do navegador, baseada em Promises, suporta async/await, não envia cookies por padrão
  • Axios: Biblioteca de terceiros, baseada em XMLHttpRequest, com interceptors, conversão automática de JSON e suporte a CSRF
  1. Otimização de Cauda (Tail Call)

Uma chamada de cauda ocorre quando uma função retorna diretamente o resultado de outra invocação de função como sua última operação:

// Chamada de cauda
function calcular(valor) {
  return processar(valor);
}

// NÃO é chamada de cauda
function calcular(valor) {
  const resultado = processar(valor);
  return resultado;
}

O benefício principal é a economia de memória, pois o contexto de execução atual pode ser descartado quando a chamada de cauda é realizada.

  1. Cópia Rasa (Shallow Copy) e Cópia Profunda (Deep Copy)

Cópia Rasa

Copia apenas o primeiro nível de propriedades. Métodos disponíveis:

  • Object.assign({}, objetoOriginal)
  • Operador spread: { ...objetoOriginal }
function copiaRasa(origem) {
  if (!origem || typeof origem !== 'object') {
    return origem;
  }
  const copia = Array.isArray(origem) ? [] : {};
  for (const propriedade of Object.keys(origem)) {
    if (origem.hasOwnProperty(propriedade)) {
      copia[propriedade] = origem[propriedade];
    }
  }
  return copia;
}

Cópia Profunda

Copia todas as propriedades recursivamente, criando novas referências. A abordagem com JSON.parse(JSON.stringify(obj)) possui limitações: perde funções, undefined e Symbols.

  1. Funções Arrow vs Funções Tradicionais

  • Arrow functions não podem ser usadas como construtoras (sem new)
  • Não possuem arguments
  • O this é herdado do contexto léxico
  • call(), apply() e bind() não alteram o this
  • Não possuem prototype

Cenários onde arrow functions não são recomendadas: métodos de objetos, protótipos, funções construtoras, callbacks com contexto dinâmico, hooks e métodos do Vue.js.

  1. Diferenças entre Set e Map

  • Set: Coleção de valores únicos, útil para remover duplicatas de arrays
  • Map: Coleção de pares chave-valor, aceita qualquer tipo como chave
  1. Diferenças entre Map e Object

  • Tipos de chave: Map aceita qualquer tipo; Object aceita apenas strings e Symbols
  • Ordem: Map preserva a ordem de inserção; Object não garante ordem
  • Iteração: Map é diretamente iterável com for...of; Object requer métodos específicos
  • Performance: Ambos oferecem operações rápidas, mas Map é mais eficiente para adições e remoções frequentes
  1. Compreensão de Promises

Uma Promise representa uma operação assíncrona futura e possui três estados:

  • Pending: Estado inicial
  • Fulfilled: Operação concluída com sucesso
  • Rejected: Operação falhou

As transições de estado são irreversíveis. A construção recebe uma função com resolve e reject:

const promessa = new Promise((resolver, rejeitar) => {
  const sucesso = true;
  if (sucesso) {
    resolver('Operação concluída');
  } else {
    rejeitar('Erro na operação');
  }
});

Comportamento de then e catch: Quando executados sem erros, retornam uma Promise fulfilled. Se houver erro, retornam uma Promise rejected. Importante: catch sem erro retorna fulfilled, acionando o próximo then.

Métodos estáticos:

  • Promise.all() - Resolve quando todas as promises resolvem; rejeita imediatamente se qualquer uma falhar
  • Promise.race() - Resolve/rejeita com o primeiro resultado
  • Promise.allSettled() - Aguarda todas completarem, independentemente do resultado
  1. Cookie, localStorage e sessionStorage

Aspecto Cookie localStorage sessionStorage
Capacidade ~4KB ~5MB ~5MB
Enviado ao servidor Sim, automaticamente Não Não
Persistência Até expiração Permanente Até fechar aba/janela
Escopo Por domínio Por domínio Por aba/janela
  1. Processo de Renderização: da URL à Página

  1. Resolução DNS: Converte domínio em endereço IP

  2. Conexão TCP: Estabelece conexão via three-way handshake

  3. Requisição HTTP: Navegador solicita recursos ao servidor

  4. Análise do HTML: Constrói a árvore DOM

  5. Análise do CSS: Constrói a árvore CSSOM

  6. Render Tree: Combina DOM e CSSOM

  7. Layout e Pintura: Calcula geometria e renderiza pixels na tela

  8. Diferença entre window.onload e DOMContentLoaded


window.addEventListener('load', () => {
  // Executa após TODOS os recursos carregarem (imagens, vídeos, etc.)
});

window.addEventListener('DOMContentLoaded', () => {
  // Executa assim que o DOM estiver pronto, recursos multimídia podem não estar prontos
});
  1. Conversão de Tipos: Explícita e Implícita

Conversão explícita: Number(), parseInt(), parseFloat(), String(), Boolean(), toString().

Conversão implícita: Ocorre em construções condicionais, operações lógicas, comparação com == e concatenação com +.

  1. O Enigma de [10,20,30].map(parseInt)

const resultado = [10, 20, 30, 221].map((elemento, indice) =>
  parseInt(elemento, indice)
);
console.log(resultado); // [10, NaN, NaN, 25]

map passa o elemento e o índice como argumentos. parseInt(10, 0) usa base 10 (resultado: 10). parseInt(20, 1) usa base inválida (NaN). parseInt(30, 2) usa base 2, onde '3' é inválido (NaN). parseInt(221, 3) usa base 3 (resultado: 25).

  1. Declaração vs Expressão de Função

// Declaração - possui hoisting
console.log(somar(5, 3)); // 8
function somar(a, b) {
  return a + b;
}

// Expressão - sem hoisting
console.log(multiplicar(5, 3)); // ReferenceError
const multiplicar = function(a, b) {
  return a * b;
};
  1. new Object() vs Object.create()

const obj1 = new Object({ x: 10, y: 20 });
const obj2 = { x: 10, y: 20 }; // Equivalente a new Object()
const obj3 = Object.create({ x: 10, y: 20 }); // Protótipo personalizado
const obj4 = Object.create(null); // Sem protótipo algum
  1. Escopo e Variáveis Livres

let contador;
for (contador = 1; contador <= 3; contador++) {
  setTimeout(() => {
    console.log(contador); // Imprime 4, 4, 4
  }, 0);
}

Como var não tem escopo de bloco (ou a variável é compartilhada), o setTimeout captura a referência final de contador (valor 4 após o loop).

  1. Implementação Manual de trim com Compatibilidade

String.prototype.trimCustom = function() {
  return this.replace(/^\s+/, '').replace(/\s+$/, '');
};

const texto = '   Olá Mundo   ';
console.log(texto.trimCustom()); // "Olá Mundo"
  1. Obtendo Parâmetros da URL

// Método tradicional
function obterParametro(nome) {
  const pesquisa = location.search.substring(1);
  const parametros = new URLSearchParams(pesquisa);
  return parametros.get(nome);
}

// Usando URLSearchParams diretamente
function obterParametroModerno(nome) {
  return new URLSearchParams(location.search).get(nome);
}
  1. requestAnimationFrame

Utilizado para animações complexas controladas por JavaScript. Diferente de setTimeout, o navegador controla automaticamente a taxa de quadros, pausa quando a aba não está visível e otimiza o processo de renderização.

  1. Por que 0.1 + 0.2 !== 0.3?

Computadores utilizam representação binária de ponto flutuante (IEEE 754). Tanto 0.1 quanto 0.2 possuem representações binárias infinitas (período 0011), resultando em arredondamentos. A soma resulta em 0.30000000000000004, que difere da representação binária de 0.3.

  1. HTMLCollection vs NodeList

  • HTMLCollection: Coleção de Elementos (ex: elemento.children, document.getElementsByTagName())
  • NodeList: Coleção de Nodes, incluindo elementos, textos e comentários (ex: document.querySelectorAll(), elemento.childNodes)

Ambos são "array-like". Conversão para array: Array.from(lista), [...lista], Array.prototype.slice.call(lista).

  1. Modo Estrito em JavaScript

Ativado com 'use strict' no início do arquivo ou função. Características:

  • Variáveis globais devem ser declaradas explicitamente
  • Uso de with é proibido
  • this em funções invocadas sem contexto é undefined (não window)
  • Parâmetros de função não podem ser duplicados
  • eval cria seu próprio escopo
  1. Requisição OPTIONS em CORS

O navegador envia automaticamente uma requisição OPTIONS (pre-flight) antes de requisições cross-origin complexas. Este mecanismo verifica se o servidor permite a operação solicitada, sem intervenção do desenvolvedor.

  1. Coleta de Lixo e Vazamento de Memória

O mecanismo de garbage collection (GC) libera automaticamente a memória ocupada por variáveis que não são mais referenciadas.

Algoritmos de Coleta

  • Contagem de referências: Algoritmo antigo que mantém contagem de referências a cada objeto. Problema: não trata referências circulares
  • Mark and Sweep: Algoritmo moderno utilizado pelo V8. Marca todos os objetos acessíveis a partir das raízes e remove os não marcados. Resolve o problema de referências circulares

Cenários Comuns de Vazamento

  • Variáveis globais não intencionais
  • Timers (setInterval) sem cancelamento
  • Referências a elementos DOM removidos
  • Closures com retenção desnecessária de variáveis
  • Event listeners não removidos ao destruir componentes
  • Em Vue: variáveis globais, timers e eventos não limpos no beforeDestroy/unmounted

Detecção

Utilizar o Chrome DevTools > Performance > gravar a sessão e clicar em "Collect garbage" para identificar crescimento anormal de memória.

  1. Event Loop no Navegador vs Node.js

Ambos seguem o mesmo princípio básico: executar código síncrono, processar microtasks e então processar macrotasks.

Node.js possui diferenças significativas:

  • Macrotasks possuem prioridades distintas em 6 fases: timers, I/O callbacks, idle/prepare, poll, check, close callbacks
  • process.nextTick tem prioridade superior a outras microtasks
  • Antes de cada fase de macrotasks, todas as microtasks pendentes são processadas
  1. Virtual DOM é Realmente Rápido?

O Virtual DOM não é mais rápido que manipulação direta do DOM. Porém, oferece uma abordagem otimizada para atualizações baseadas em mudanças de estado, comparando representações virtuais e aplicando apenas as diferenças necessárias ao DOM real.

  1. Performance: for vs forEach

for é mais rápido que forEach, pois este último invoca uma função callback a cada iteração, criando um novo contexto de execução e adicionando overhead.

  1. Princípio do JS Bridge

JS Bridge permite que código JavaScript em WebViews se comunique com APIs nativas do aplicativo. Implementações comuns:

  • API global exposta: O cliente adiciona métodos ao objeto window (ex: window.obterVersao()). Operações síncronas
  • Interceptação de URL Scheme: Protocolos customizados (ex: minha-app://api/dados) são interceptados pelo aplicativo que processa e retorna resultados
  1. requestIdleCallback vs requestAnimationFrame

  • requestAnimationFrame: Executa antes de cada repaint, ideal para animações de alto desempenho
  • requestIdleCallback: Executa durante períodos ociosos do navegador, ideal para tarefas de baixa prioridade como pré-carregamento de dados
  1. Atraso de 300ms em Clique Mobile

Navegadores antigos aguardavam 300ms para detectar double-tap (zoom). Soluções:

  • Configurar <meta name="viewport" content="width=device-width, initial-scale=1.0"> (Chrome 32+)
  • Utilizar bibliotecas como FastClick para navegadores mais antigos
  1. Token vs Cookie em Autenticação

Aspecto Cookie Token (JWT)
Envio Automático pelo navegador Manual (header Authorization)
Cross-origin Limitado por domínio Sem restrições
Carga no servidor Alta (verificação a cada requisição) Baixa (verificação local)
Armazenamento de dados Limitado (~4KB) Flexível
  1. Autenticação: Session vs JWT

Baseado em Session

  1. Usuário envia credenciais ao servidor
  2. Servidor cria sessão e armazena em banco de dados
  3. Servidor envia sessionId via Set-Cookie
  4. Requisições subsequentes incluem o cookie automaticamente

Prós: Simples, dados no servidor. Contras: Consome memória do servidor, difícil sincronização em múltiplos servidores.

Baseado em JWT

  1. Usuário envia credenciais ao servidor
  2. Servidor gera token JWT com informações do usuário
  3. Cliente armazena e envia token no header Authorization
  4. Servidor apenas verifica a validade do token

Prós: Stateless, sem restrição cross-origin, escalável. Contras: Tokens maiores, dificuldade em invalidar tokens individualmente.

  1. Single Sign-On (SSO)

SSO permite que usuários acessem múltiplos sistemas com uma única autenticação.

Implementação para mesmo domínio

Configurar cookie com domain para o domínio raiz:

document.cookie = "sessionId=abc123; domain=exemplo.com; path=/"

Implementação para domínios diferentes

Utilizar um centro de autenticação centralizado:

  1. Usuário acessa siteA.com e é redirecionado ao centro de autenticação

  2. Após login, o centro gera token e redireciona de volta com o token na URL

  3. Ao acessar siteB.com, o centro verifica o cookie existente e fornece o token

  4. O siteB valida o token com o centro e armazena localmente

  5. Atributos defer e async na tag script


  • Sem atributo: Pausa HTML, baixa e executa o script imediatamente
  • async: Download paralelo com HTML, execução pausa o HTML
  • defer: Download paralelo com HTML, execução somente após conclusão da análise do HTML
  1. preload vs prefetch

  • preload: Carrega recursos críticos da página atual com alta prioridade. Bloqueia renderização até conclusão
  • prefetch: Carrega recursos que podem ser necessários futuramente, em segundo plano com baixa prioridade
<!-- Recursos críticos para a página atual -->
<link rel="preload" href="estilos.css" as="style">
<link rel="preload" href="principal.js" as="script">

<!-- Recursos para navegação futura -->
<link rel="prefetch" href="proxima-pagina.js" as="script">
  1. dns-prefetch e preconnect

  • dns-prefetch: Resolve o endereço DNS antecipadamente
  • preconnect: Estabelece conexão completa (DNS + TCP + TLS) antecipadamente

Úteis para reduzir latência ao acessar recursos de terceiros.

  1. WebSocket vs HTTP

  • HTTP: Protocolo stateless, comunicação unidirecional (cliente inicia), nova conexão a cada requisição
  • WebSocket: Conexão persistente, comunicação bidirecional em tempo real, ideal para chat, jogos online e atualizações em tempo real
  1. Comunicação entre Abas do Navegador

Via localStorage

// Tab 1 - Escrita
localStorage.setItem('notificacao', JSON.stringify({ tipo: 'atualizacao' }));

// Tab 2 - Leitura via evento
window.addEventListener('storage', (evento) => {
  if (evento.key === 'notificacao') {
    const dados = JSON.parse(evento.newValue);
    console.log('Atualização recebida:', dados);
  }
});

Via BroadcastChannel

// Tab 1
const canal = new BroadcastChannel('comunicacao');
canal.postMessage({ acao: 'atualizar' });

// Tab 2
const canal = new BroadcastChannel('comunicacao');
canal.onmessage = (evento) => {
  console.log('Mensagem recebida:', evento.data);
};
  1. Comunicação entre iframes

Utilizar postMessage para comunicação segura:

// Enviar mensagem do iframe para o pai
window.parent.postMessage({ tipo: 'status', valor: 'pronto' }, 'https://dominio-pai.com');

// Pai escutando mensagens do iframe
window.addEventListener('message', (evento) => {
  if (evento.origin === 'https://dominio-filho.com') {
    console.log('Dados recebidos:', evento.data);
  }
});

// Pai enviando mensagem para o iframe
document.getElementById('meuIframe').contentWindow.postMessage(
  { tipo: 'comando', acao: 'carregar' },
  'https://dominio-filho.com'
);
  1. Otimização de Primeira Tela (First Contentful Paint)

  • Lazy loading de rotas: Carregar apenas os componentes necessários para a rota atual
  • Renderização no servidor (SSR): Nuxt.js para Vue, Next.js para React
  • Pré-busca no aplicativo: Em WebViews, o app nativo pode pré-carregar dados
  • Paginação: Carregar conteúdo incrementalmente conforme necessário
  • Lazy loading de imagens: Atrasar carregamento de imagens fora da viewport
  • Pacotes offline: Armazenar recursos estáticos localmente no aplicativo
  1. Renderização de Grande Volume de Dados

Para 100.000 itens de dados, utilizar lista virtual:

  • Renderiza apenas itens visíveis na viewport
  • Elementos fora da view são representados por um container com altura calculada
  • Ao rolar, itens são criados e destruídos dinamicamente
  • Bibliotecas recomendadas: vue-virtual-scroller, react-virtualized, react-window
  1. Diagnóstico de Performance em H5

Ferramentas

  • Chrome DevTools (Performance): Métricas como FP, FCP, LCP, DCL e window.onload
  • Lighthouse: Ferramenta automatizada com relatório detalhado e sugestões de otimização
# Instalação e uso do Lighthouse
npm install -g lighthouse
lighthouse https://exemplo.com --view --preset=mobile

Identificação de Problemas

  • Carregamento lento: Otimizar APIs, usar CDN, comprimir assets, code splitting
  • Renderização lenta: SSR, otimização de first paint, skeleton screens
  1. Questões Avançadas de Código

Propriedades de Construtor e Protótipo

function Veiculo() {
  Veiculo.tipo = function() { console.log('estatico') };
  this.tipo = function() { console.log('instancia') };
}
Veiculo.prototype.tipo = function() { console.log('prototipo') };
Veiculo.tipo = function() { console.log('inicial') };

Veiculo.tipo();           // "inicial"
const carro = new Veiculo();
carro.tipo();             // "instancia"
Veiculo.tipo();           // "estatico"

Explicação: Primeiro, Veiculo.tipo() executa a atribuição estática inicial, imprimindo "inicial". Após new Veiculo(), o construtor redefine Veiculo.tipo e adiciona método à instância. carro.tipo() encontra o método na instância. Veiculo.tipo() agora executa a versão redefinida pelo construtor.

Encadeamento de Promises

Promise.resolve().then(() => {
  console.log('A');
  return Promise.resolve('B');
}).then((resultado) => {
  console.log(resultado);
});

Promise.resolve().then(() => {
  console.log('C');
}).then(() => {
  console.log('D');
}).then(() => {
  console.log('E');
}).then(() => {
  console.log('F');
}).then(() => {
  console.log('G');
});

// Saída: A, C, D, E, B, F, G

Quando then retorna uma Promise, ocorre um atraso de dois ciclos ("slow two beats"): aguarda a resolução da Promise interna e depois agenda o próximo then como microtask.

Atribuição Encadeada e Prioridade do Operador

let objA = { valor: 1 };
let objB = objA;
objA.prop = objA = { valor: 2 };

console.log(objA.prop); // undefined
console.log(objB.prop); // { valor: 2 }

Explicação: O operador . tem prioridade sobre =. Primeiro, objA.prop é inicializado como undefined no objeto original { valor: 1 }. Depois, a atribuição encadeada é executada da direita para a esquerda: objA recebe { valor: 2 }, e objA.prop (referindo-se ao objeto original via objB) recebe a nova referência.

Chaves de Objetos e Conversão de Tipos

// Exemplo 1: Números como chaves
const dados1 = {};
const chave1 = '123';
const chave2 = 123;
dados1[chave1] = 'a';
dados1[chave2] = 'b';
console.log(dados1[chave1]); // "b" (123 é convertido para "123")

// Exemplo 2: Symbols como chaves
const dados2 = {};
const simboloA = Symbol('id');
const simboloB = Symbol('id');
dados2[simboloA] = 'x';
dados2[simboloB] = 'y';
console.log(dados2[simboloA]); // "x" (Symbols são únicos)

// Exemplo 3: Objetos como chaves
const dados3 = {};
const obj1 = { nome: 'teste' };
const obj2 = { nome: 'outro' };
dados3[obj1] = 'alpha';
dados3[obj2] = 'beta';
console.log(dados3[obj1]); // "beta" (ambos convertem para "[object Object]")

Propriedades de objetos em JavaScript são convertidas para strings. Números tornam-se strings numéricas, objetos invocam toString() resultando em "[object Object]", e Symbols mantêm sua unicidade.

Tags: javascript ecmascript async ES6 promises

Publicado em 6-24 16:56