$cd~/artigos/primitive-types-blocos-construcao-javascript
Fundamentals
série 33 Conceitos JS·parte 6 de 38

Primitive Types: Os 7 Blocos de Construção do JavaScript

10 minVanderlei José Alamino

Qual a diferença entre "hello" e { text: "hello" }? Por que você pode chamar "hello".toUpperCase() se strings não são objetos? E por que typeof null retorna "object"?

Se essas perguntas já te passaram pela cabeça, você está no lugar certo. Neste artigo, vamos desmontar os 7 tipos primitivos do JavaScript — os átomos de toda a linguagem. Tudo que você constrói em JavaScript, desde um simples objeto até uma aplicação inteira, descansa sobre esses blocos fundamentais.

Você vai entender por que primitivos são imutáveis, como funciona o autoboxing (a mágica que permite "texto".length), a diferença entre undefined e null, e os quirks clássicos como typeof null === "object". Cada tipo é explorado com exemplos copiáveis, analogias visuais e perguntas de entrevista no final do artigo.

Os sete tipos são: string, number, bigint, boolean, undefined, null e symbol. Dominá-los é o primeiro passo da trilha Fundamentals — em seguida você compara primitivos com objetos em Primitives vs Objects, mergulha em coerção em Type Coercion e fecha a trilha com Equality Operators.

Este guia faz parte da série 33 Conceitos JS — tradução e adaptação do projeto open source 33jsconcepts.com. Reserve cerca de 10 minutos de leitura focada; ao final, você terá um mapa mental sólido para interpretar qualquer valor que aparecer no seu código.

primitive-types-blocos-construcao-javascript.meta.jsonjson

// metadados do artigo

{
  "tag": "fundamentos",
  "readTime": "10 min",
  "author": "Vanderlei José Alamino",
  "source": "33jsconcepts.com",
  "series": "33 Conceitos JS",
  "part": {
    "current": 6,
    "total": 38
  }
}
abrir fonte original
primitive-types-blocos-construcao-javascript.mdmarkdown

Fonte de referência

Conteúdo adaptado a partir do guia original em inglês.

33jsconcepts.com
01

seção

O que são Tipos Primitivos?

Em JavaScript, um primitivo é um dado que não é um objeto e não possui métodos próprios. Segundo a especificação ECMAScript 2024 (ECMA-262), o JavaScript tem exatamente 7 tipos primitivos:

TipoExemploDescrição
string"hello"Dados de texto
number42, 3.14Dados numéricos (inteiros e decimais)
bigint9007199254740993nInteiros muito grandes
booleantrue, falseValores lógicos
undefinedundefinedNenhum valor atribuído
nullnullAusência intencional de valor
symbolSymbol("id")Identificador único

Três Características Fundamentais

Todos os primitivos compartilham estes traços fundamentais:

1. Imutáveis — valores não podem ser alterados

Uma vez criado, um valor primitivo não pode ser modificado. Quando você "altera" uma string, na verdade está criando uma nova string.

snippetJavaScript
let name = "Alice";name.toUpperCase();    // Cria "ALICE", mas não altera 'name'console.log(name);     // Ainda "Alice"

2. Comparados por valor

Quando você compara dois primitivos, o JavaScript compara os valores reais — não onde estão armazenados na memória.

snippetJavaScript
let a = "hello";let b = "hello";console.log(a === b);  // true — mesmo valor let obj1 = { text: "hello" };let obj2 = { text: "hello" };console.log(obj1 === obj2);  // false — objetos diferentes!

3. Sem métodos (mas com a mágica do autoboxing)

Primitivos não têm métodos, mas o JavaScript os envolve automaticamente em objetos quando você tenta chamar métodos. Isso se chama autoboxing.

snippetJavaScript
"hello".toUpperCase();  // Funciona! O JS envolve "hello" em um objeto String

Vamos explorar essa mágica em detalhes mais adiante.

02

seção

A Analogia dos Átomos vs Moléculas

Pense nos dados em JavaScript como na aula de química (só que bem mais divertida, e sem óculos de proteção). Primitivos são como átomos: os blocos fundamentais, indivisíveis, que não podem ser decompostos. Objetos são como moléculas: estruturas complexas formadas pela combinação de vários átomos.

Assim como os átomos são a fundação de toda matéria, os primitivos são a fundação de todos os dados em JavaScript. Toda estrutura complexa que você cria — arrays, objetos, funções — é construída sobre esses valores primitivos simples.

03

seção

Os 7 Tipos Primitivos: Aprofundamento

Vamos explorar cada tipo primitivo em detalhes.

String

Uma string representa dados de texto: uma sequência de caracteres.

snippetJavaScript
// Três formas de criar stringslet single = 'Hello';           // Aspas simpleslet double = "World";           // Aspas duplaslet backtick = `Hello World`;   // Template literal (ES6)

Template Literals (ainda são strings!)

Template literals (crases) não são um tipo separado. São apenas uma sintaxe mais poderosa para criar strings. O resultado continua sendo uma string primitiva:

snippetJavaScript
let name = "Alice";let age = 25; // Interpolação de string — embute expressõeslet greeting = `Olá, ${name}! Você tem ${age} anos.`;console.log(greeting);        // "Olá, Alice! Você tem 25 anos."console.log(typeof greeting); // "string" — é só uma string! // Strings multilinhalet multiLine = `  Esta é a linha 1  Esta é a linha 2`;console.log(typeof multiLine); // "string"

Strings são imutáveis

Você não pode alterar caracteres individuais em uma string:

snippetJavaScript
let str = "hello";str[0] = "H";        // Não faz nada! Sem erro, mas sem mudançaconsole.log(str);    // Ainda "hello" // Para "alterar" uma string, crie uma novastr = "H" + str.slice(1);console.log(str);    // "Hello"

Métodos como toUpperCase(), slice(), replace() sempre retornam novas strings. Eles nunca modificam a original.

Number

O JavaScript tem apenas um tipo numérico para inteiros e decimais. Todos os números são armazenados como ponto flutuante de 64 bits (padrão IEEE 754).

snippetJavaScript
let integer = 42;        // Inteirolet decimal = 3.14;      // Decimallet negative = -10;      // Negativolet scientific = 2.5e6;  // 2.500.000 (notação científica)

Valores numéricos especiais

snippetJavaScript
console.log(1 / 0);       // Infinityconsole.log(-1 / 0);      // -Infinityconsole.log("hello" * 2); // NaN (Not a Number)

O JavaScript tem valores especiais: Infinity para valores grandes demais para representar, e NaN (Not a Number) para operações matemáticas inválidas.

O famoso problema de ponto flutuante

snippetJavaScript
console.log(0.1 + 0.2);           // 0.30000000000000004console.log(0.1 + 0.2 === 0.3);   // false! Bem-vindo ao JavaScript!

Isso não é um bug do JavaScript — segue o padrão IEEE 754 de ponto flutuante de dupla precisão usado por praticamente todas as linguagens modernas. O decimal 0.1 não pode ser representado perfeitamente em binário.

Trabalhando com dinheiro? Nunca use ponto flutuante para cálculos! Armazene valores em centavos como inteiros e use Intl.NumberFormat para exibição.

snippetJavaScript
// Ruim: erros de ponto flutuante nos cálculoslet price = 0.1 + 0.2;  // 0.30000000000000004 // Bom: calcule em centavos, formate para exibiçãolet priceInCents = 10 + 20;  // 30 (cálculo preciso!) const formatter = new Intl.NumberFormat('pt-BR', {  style: 'currency',  currency: 'BRL',});console.log(formatter.format(priceInCents / 100));  // "R$ 0,30"

Intl.NumberFormat é nativo do JavaScript. Sem bibliotecas externas! Ele cuida de símbolos de moeda, separadores decimais e formatação por locale automaticamente.

Faixa segura de inteiros

snippetJavaScript
console.log(Number.MAX_SAFE_INTEGER);  // 9007199254740991 (2^53 - 1)console.log(Number.MIN_SAFE_INTEGER);  // -9007199254740991

Number.MAX_SAFE_INTEGER é o maior inteiro que pode ser representado com segurança. Além dessa faixa, a precisão se perde:

snippetJavaScript
console.log(9007199254740992 === 9007199254740993);  // true! (errado!)

Para inteiros maiores, use BigInt.

BigInt

BigInt (ES2020) representa inteiros maiores que Number.MAX_SAFE_INTEGER.

snippetJavaScript
let big = 9007199254740993n;let alsoBig = BigInt("9007199254740993"); console.log(big + 1n);  // 9007199254740994n (correto!)

Regras do BigInt

snippetJavaScript
let big = 10n;let regular = 5;// console.log(big + regular);  // TypeError! console.log(big + BigInt(regular));  // 15nconsole.log(Number(big) + regular);  // 15

Quando usar BigInt: criptografia, timestamps precisos, IDs de banco de dados, qualquer cálculo que exija inteiros maiores que 9 quatrilhões.

Boolean

Boolean tem exatamente dois valores: true e false.

snippetJavaScript
let isLoggedIn = true;let hasPermission = false; let isAdult = age >= 18;let isEqual = name === "Alice";

Truthy e Falsy

Em contextos booleanos (como if), todos os valores são "truthy" ou "falsy":

snippetJavaScript
// Valores falsy (só 8!)false0-00n        // BigInt zero""        // String vazianullundefinedNaN // Todo o resto é truthy"hello"   // truthy42        // truthy[]        // truthy (array vazio!){}        // truthy (objeto vazio!)
snippetJavaScript
let value = "hello";let bool = Boolean(value);  // truelet shortcut = !!value;     // true (truque da dupla negação)

undefined

undefined significa "nenhum valor foi atribuído". O JavaScript o usa automaticamente em várias situações:

snippetJavaScript
// 1. Declarado mas não atribuídolet x;console.log(x);  // undefined // 2. Parâmetro de função ausentefunction greet(name) {  console.log(name);}greet(); // 3. Função sem returnfunction doNothing() {}console.log(doNothing());  // undefined // 4. Propriedade inexistentelet person = { name: "Alice" };console.log(person.age);  // undefined

Não atribua undefined explicitamente a variáveis. Use null para indicar "vazio intencional".

null

null significa "vazio intencional". Você está dizendo explicitamente: "isso não tem valor".

snippetJavaScript
let user = { name: "Alice" };user = null;  // Usuário deslogou, limpando a referência function findUser(id) {  return null;  // Usuário não encontrado}

O famoso bug do typeof

snippetJavaScript
console.log(typeof null);  // "object" — Espera, o quê?!

Sim, de verdade. É um dos quirks mais famosos do JavaScript! Um erro histórico da primeira implementação em 1995. Nunca foi corrigido porque muito código existente depende disso.

snippetJavaScript
let value = null;console.log(value === null);  // true (use igualdade estrita)

Symbol

Symbol (ES6) cria identificadores únicos. Mesmo símbolos com a mesma descrição são diferentes.

snippetJavaScript
let id1 = Symbol("id");let id2 = Symbol("id"); console.log(id1 === id2);  // false — sempre únicos!console.log(id1.description);  // "id"

Caso de uso: chaves únicas em objetos

snippetJavaScript
const ID = Symbol("id");const user = {  name: "Alice",  [ID]: 12345}; console.log(user.name);    // "Alice"console.log(user[ID]);     // 12345console.log(Object.keys(user));  // ["name"] — ID não aparece

Well-Known Symbols

O JavaScript tem símbolos embutidos para customizar comportamento de objetos: Symbol.iterator, Symbol.toStringTag, Symbol.toPrimitive, entre outros.

Symbols são um recurso avançado. Como iniciante, foque em entender que eles existem e criam valores únicos. Você os encontrará em padrões avançados e código de bibliotecas.

04

seção

O Operador typeof

O operador typeof retorna uma string indicando o tipo de um valor.

snippetJavaScript
console.log(typeof "hello");     // "string"console.log(typeof 42);          // "number"console.log(typeof 42n);         // "bigint"console.log(typeof true);        // "boolean"console.log(typeof undefined);   // "undefined"console.log(typeof Symbol());    // "symbol"console.log(typeof null);        // "object" ⚠️ (bug!)console.log(typeof {});          // "object"console.log(typeof []);          // "object"console.log(typeof function(){}); // "function"

Tabela de resultados do typeof

ValorResultado do typeofNotas
"hello""string"
42"number"
42n"bigint"
true / false"boolean"
undefined"undefined"
Symbol()"symbol"
null"object"Bug histórico!
{}"object"
[]"object"Arrays são objetos
function(){}"function"Funções são especiais

Verificação de tipo mais confiável

Como o typeof tem quirks, aqui estão alternativas mais confiáveis:

snippetJavaScript
let value = null;if (value === null) {  console.log("É null");} Array.isArray([1, 2, 3]);  // trueArray.isArray("hello");    // false Object.prototype.toString.call(null);       // "[object Null]"Object.prototype.toString.call([]);         // "[object Array]"Object.prototype.toString.call(new Date()); // "[object Date]"

Array.isArray() é a forma confiável de verificar arrays, já que typeof [] retorna "object". Para verificações mais complexas, Object.prototype.toString() dá informação precisa do tipo.

05

seção

Imutabilidade Explicada

Imutável significa "não pode ser alterado". Valores primitivos são imutáveis — você não pode modificar o valor em si.

Vendo a imutabilidade em ação

snippetJavaScript
let str = "hello"; str.toUpperCase();     // Retorna "HELLO"console.log(str);      // Ainda "hello"! str = str.toUpperCase();console.log(str);      // Agora "HELLO"

Visual: o que acontece na memória

Equívoco comum: const vs imutabilidade

Muita gente ouve que primitivos são imutáveis e conclui que const "congela" qualquer valor. Não é bem assim. const impede reatribuição, não mutação — são regras sobre coisas diferentes.

Reatribuição: trocar para onde a variável aponta

Uma variável é como uma etiqueta colada em um valor na memória. Reatribuir significa arrancar a etiqueta e colá-la em outro valor:

snippetJavaScript
let cargo = "Alice";cargo = "Bob";  // OK com let — a etiqueta agora aponta para "Bob" const cargoFixo = "Alice";// cargoFixo = "Bob";  // Erro! const trava a etiqueta — ela não pode apontar para outro valor

Com const, o JavaScript garante: essa variável sempre apontará para o mesmo valor que recebeu na declaração. Isso é reatribuição — e const bloqueia isso.

Mutação: alterar o conteúdo por dentro

Mutar é diferente: você não troca a etiqueta, mas mexe no que está "dentro" do valor — desde que esse valor seja mutável (como um objeto ou array).

snippetJavaScript
const person = { name: "Alice" }; person.name = "Bob";  // Mutação — altera uma propriedade do objetoperson.age = 25;      // Mutação — adiciona propriedade// person = {};      // Reatribuição — ERRO! Tentaria apontar para outro objeto

O objeto continua sendo o mesmo objeto na memória; só o conteúdo interno mudou. const não impede isso — ele só impede que person passe a referenciar um objeto diferente.

Imutabilidade: propriedade do valor, não da variável

Primitivos (string, number, boolean…) são imutáveis por natureza: o valor em si não pode ser alterado, independentemente de const ou let.

snippetJavaScript
let str = "hello";str[0] = "H";  // Não funciona — strings não permitem mutação de caracteres const name = "Alice";// name = "Bob";  // Erro — reatribuição bloqueada pelo const

Com let, você poderia reatribuir str = "Hello", mas isso cria uma string nova — não modifica "hello" original. A imutabilidade é do valor primitivo; o const/let só controla se a variável pode apontar para outro valor.

Resumo visual

ConceitoO que protegeExemplo bloqueadoExemplo permitido
constA variável (etiqueta)person = {}person.name = "Bob"
ImutabilidadeO valor primitivo (conteúdo)str[0] = "H"str = str + "!" (nova string)
snippetJavaScript
const name = "Alice";// name = "Bob";  // Erro! Não pode reatribuir const const person = { name: "Alice" };person.name = "Bob";     // Funciona! Mutando o objetoperson.age = 25;         // Funciona! Adicionando propriedade// person = {};          // Erro! Não pode reatribuir const let str = "hello";str[0] = "H";  // Falha silenciosamente — não dá para mutar primitivo

Regra prática: const protege a variável (o container). Imutabilidade protege o valor primitivo (o conteúdo). Objetos em const ainda podem ser mutados — se você precisa de um objeto que não mude, use técnicas como Object.freeze() (assunto para outro artigo).

06

seção

Autoboxing: A Vida Secreta dos Primitivos

Se primitivos não têm métodos, como "hello".toUpperCase() funciona?

A mágica por trás dos panos

Quando você acessa uma propriedade ou método em um primitivo, o JavaScript o envolve temporariamente em um objeto:

Você chama um método em um primitivo

snippetJavaScript
"hello".toUpperCase()

O JavaScript cria um objeto wrapper

Por trás dos panos, algo como:

snippetJavaScript
(new String("hello")).toUpperCase()

O método executa e retorna

O método toUpperCase() roda e retorna "HELLO".

O objeto wrapper é descartado

O objeto String temporário é jogado fora. O primitivo original "hello" permanece inalterado.

Objetos wrapper

Cada tipo primitivo (exceto null e undefined) tem um objeto wrapper correspondente:

PrimitivoObjeto Wrapper
stringString
numberNumber
booleanBoolean
bigintBigInt
symbolSymbol

Não use new String() etc.

Você pode criar objetos wrapper manualmente, mas não faça isso:

snippetJavaScript
let strObj = new String("hello");console.log(typeof strObj);        // "object" (não "string"!)console.log(strObj === "hello");   // false (objeto vs primitivo) let str = "hello";console.log(typeof str);           // "string"

Usar new String(), new Number() ou new Boolean() cria objetos, não primitivos. Isso causa bugs confusos com igualdade e typeof.

07

seção

null vs undefined

Esses dois valores "vazios" confundem muitos desenvolvedores. Veja como diferem:

Comparação lado a lado

Aspectoundefinednull
Significado"Nenhum valor atribuído ainda""Vazio intencional"
Definido porJavaScript automaticamenteDesenvolvedor explicitamente
typeof"undefined""object" (bug)
Em JSONOmitido da saídaPreservado como null
Parâmetros defaultDispara o defaultNão dispara o default
Igualdade soltanull == undefined é true
Igualdade estritanull === undefined é false

Quando o JavaScript usa undefined

snippetJavaScript
let x;console.log(x);  // undefined function greet(name) {  console.log(name);}greet();  // undefined function noReturn() {}console.log(noReturn());  // undefined let obj = {};console.log(obj.missing);  // undefined let arr = [1, , 3];console.log(arr[1]);  // undefined

Quando usar null

snippetJavaScript
let user = { name: "Alice" };user = null; function findUser(id) {  return null;} let config = {  cache: true,  timeout: null}; let timer = setTimeout(callback, 1000);clearTimeout(timer);timer = null;

Boas práticas

snippetJavaScript
if (value == null) {  console.log("Valor é null ou undefined");} if (value === undefined) {  console.log("Valor é undefined");} if (value === null) {  console.log("Valor é null");} if (value != null) {  console.log("Valor existe");}
08

seção

Quirks e Gotchas do JavaScript

O erro #1 com primitivos: usar construtores wrapper

O erro mais comum com primitivos é usar new String(), new Number() ou new Boolean() em vez de literais.

snippetJavaScript
const str = new String("hello");console.log(typeof str);        // "object" (não "string"!)console.log(str === "hello");   // false const str2 = "hello";console.log(typeof str2);       // "string"console.log(str2 === "hello");  // true

Regra de ouro: Nunca use new com String, Number ou Boolean. Para conversão de tipo, use-os como funções sem new: String(123) retorna "123" (um primitivo).

1. typeof null === 'object'

snippetJavaScript
console.log(typeof null);  // "object"

Por quê? Bug da primeira implementação em 1995. Valores tinham tags de tipo; objetos e null compartilhavam a tag 000. Nunca foi corrigido porque muito código depende disso.

snippetJavaScript
if (value !== null && typeof value === "object") {  // É um objeto de verdade}

2. NaN !== NaN

snippetJavaScript
console.log(NaN === NaN);  // false!console.log(NaN !== NaN);  // true!

NaN é tão confuso que não é igual a si mesmo! Pela especificação IEEE 754, NaN representa resultado indefinido — não pode ser igual a nada, nem a si.

snippetJavaScript
if (Number.isNaN(value)) { }  // ES6, recomendadoif (isNaN(value)) { }         // Mais antigo, tem quirks

isNaN() converte o valor primeiro, então isNaN("hello") é true. Number.isNaN() só retorna true para NaN real.

3. 0.1 + 0.2 !== 0.3

snippetJavaScript
console.log(0.1 + 0.2);         // 0.30000000000000004console.log(0.1 + 0.2 === 0.3); // false

Computadores armazenam números em binário. Assim como 1/3 não tem representação decimal exata (0,333...), 0.1 não tem representação binária exata.

snippetJavaScript
let totalCents = 10 + 20;let reais = totalCents / 100; new Intl.NumberFormat('pt-BR', {  style: 'currency',  currency: 'BRL'}).format(0.30); Math.abs((0.1 + 0.2) - 0.3) < Number.EPSILON;(0.1 + 0.2).toFixed(2);  // "0.30"

4. String vazia é falsy, mas...

snippetJavaScript
console.log(Boolean(""));      // falseconsole.log(Boolean(" "));     // true (espaço é truthy!)console.log(Boolean("0"));     // true (string "0" é truthy!)console.log(Boolean(0));       // false console.log("" == false);      // true (coerção)console.log("" === false);     // false
snippetJavaScript
if (str.trim() === "") {  console.log("String vazia ou só espaços");}

5. Operador + e concatenação de strings

snippetJavaScript
console.log(1 + 2);        // 3console.log("1" + "2");    // "12"console.log(1 + "2");      // "12"console.log("1" + 2);      // "12"console.log(1 + 2 + "3");  // "33"console.log("1" + 2 + 3);  // "123"

O operador + faz adição para números, mas concatenação para strings. Quando misturado, o JavaScript converte números para strings.

snippetJavaScript
Number("1") + Number("2");  // 3String(1) + String(2);      // "12"`${1}${2}`;                 // "12"
09

seção

Teste Seu Conhecimento

$ summary --quick

Resumo rápido

  • 7 primitivos: string, number, bigint, boolean, undefined, null, symbol
  • Primitivos são imutáveis — você não altera o valor em si, apenas cria novos valores
  • Comparados por valor — "hello" === "hello" é true porque os valores coincidem
  • typeof funciona para a maioria dos tipos — exceto typeof null retorna "object" (bug histórico)
  • Autoboxing permite que primitivos usem métodos — o JavaScript os envolve temporariamente
  • undefined vs null — undefined é "não atribuído"; null é "vazio intencional"
  • Fique atento aos gotchas — NaN !== NaN, 0.1 + 0.2 !== 0.3, valores falsy
  • Não use new String() etc. — cria objetos, não primitivos
  • Symbols criam identificadores únicos — mesmo Symbol("id") !== Symbol("id")
  • Use Number.isNaN() para verificar NaN — nunca use igualdade, pois NaN !== NaN

Créditos da série

Este artigo faz parte de uma série de estudos inspirada no projeto 33 Conceitos JS, criado por Leonardo Maldonado. Todo o conteúdo original está disponível em 33jsconcepts.com.