Parâmetros padrão, rest e spread operator
1. Parâmetros Padrão (Default Parameters)
Os parâmetros padrão permitem definir valores iniciais para argumentos de funções quando nenhum valor ou undefined é passado. A sintaxe é direta:
function saudacao(nome = "Visitante") {
return `Olá, ${nome}!`;
}
console.log(saudacao("Maria")); // Olá, Maria!
console.log(saudacao()); // Olá, Visitante!
É importante entender que apenas undefined aciona o valor padrão. Outros valores falsy como null, 0 ou "" são mantidos:
function testar(valor = "padrão") {
return valor;
}
console.log(testar(undefined)); // "padrão"
console.log(testar(null)); // null
console.log(testar(0)); // 0
console.log(testar("")); // ""
Valores padrão podem ser expressões ou resultados de funções:
function gerarId(prefixo = "user", timestamp = Date.now()) {
return `${prefixo}_${timestamp}`;
}
console.log(gerarId()); // user_1697123456789
2. Parâmetros Padrão no Contexto de Node.js e React
No React, parâmetros padrão evitam erros em handlers de eventos:
function Botao({ onClick = () => {}, texto = "Clique aqui" }) {
return <button onClick={onClick}>{texto}</button>;
}
Em middlewares do Express (Node.js), valores padrão configuram opções:
function loggerMiddleware(opcoes = { nivel: "info", formato: "json" }) {
return (req, res, next) => {
console.log(`[${opcoes.nivel}] ${req.method} ${req.url}`);
next();
};
}
app.use(loggerMiddleware());
app.use(loggerMiddleware({ nivel: "debug" }));
Exemplo prático: componente React com props opcionais:
function Card({ titulo = "Sem título", conteudo = "", corFundo = "#fff" }) {
return (
<div style={{ backgroundColor: corFundo, padding: "20px" }}>
<h2>{titulo}</h2>
<p>{conteudo}</p>
</div>
);
}
// Uso
<Card titulo="Meu Card" conteudo="Conteúdo personalizado" />
<Card /> // Renderiza com valores padrão
3. Parâmetros Rest (...args)
O operador rest coleta argumentos restantes em um array real, diferentemente do objeto arguments que é array-like:
function somarTodos(...numeros) {
return numeros.reduce((acc, num) => acc + num, 0);
}
console.log(somarTodos(1, 2, 3, 4)); // 10
// Comparação com arguments
function usandoArguments() {
return Array.from(arguments).reduce((acc, val) => acc + val, 0);
}
Rest em arrow functions e métodos de classe:
const multiplicar = (multiplicador, ...numeros) => {
return numeros.map(n => n * multiplicador);
};
console.log(multiplicar(2, 1, 2, 3)); // [2, 4, 6]
class Calculadora {
somar(...valores) {
return valores.reduce((acc, v) => acc + v, 0);
}
}
4. Parâmetros Rest em Node.js e React
Funções utilitárias com número variável de argumentos:
// utils/formatacao.js
function formatarMensagem(template, ...valores) {
return valores.reduce((msg, val, i) => {
return msg.replace(`{${i}}`, val);
}, template);
}
console.log(formatarMensagem("Olá {0}, hoje é {1}", "João", "segunda-feira"));
Hooks personalizados com parâmetros dinâmicos:
function useFormulario(estadoInicial = {}, ...validadores) {
const [dados, setDados] = React.useState(estadoInicial);
const [erros, setErros] = React.useState({});
const validar = () => {
const novosErros = {};
validadores.forEach(validador => {
const resultado = validador(dados);
if (resultado) Object.assign(novosErros, resultado);
});
setErros(novosErros);
return Object.keys(novosErros).length === 0;
};
return { dados, erros, setDados, validar };
}
Função de logging flexível em servidor Node.js:
function logServidor(nivel, mensagem, ...metadados) {
const entrada = {
timestamp: new Date().toISOString(),
nivel,
mensagem,
metadados: metadados.length > 0 ? metadados : undefined
};
console.log(JSON.stringify(entrada));
}
logServidor("INFO", "Servidor iniciado");
logServidor("ERRO", "Falha na conexão", { db: "mongo" }, { tentativa: 3 });
5. Spread Operator em Arrays e Objetos
Propagação de arrays para cópia, concatenação e inserção:
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
// Cópia
const copia = [...arr1];
// Concatenação
const combinado = [...arr1, ...arr2]; // [1, 2, 3, 4, 5, 6]
// Inserção
const comItem = [0, ...arr1, 4]; // [0, 1, 2, 3, 4]
Propagação de objetos para clonagem rasa e mesclagem:
const usuario = { nome: "Ana", idade: 30 };
const endereco = { cidade: "São Paulo", uf: "SP" };
// Clonagem rasa
const clone = { ...usuario };
// Mesclagem
const completo = { ...usuario, ...endereco };
// { nome: "Ana", idade: 30, cidade: "São Paulo", uf: "SP" }
// Ordem importa: propriedades posteriores sobrescrevem anteriores
const atualizado = { ...usuario, idade: 31 };
Uso com destructuring:
const pessoa = { nome: "Carlos", idade: 25, email: "carlos@email.com" };
const { nome, ...resto } = pessoa;
console.log(nome); // "Carlos"
console.log(resto); // { idade: 25, email: "carlos@email.com" }
6. Spread Operator no Contexto de React
Atualização imutável de estado com hooks:
function ListaTarefas() {
const [tarefas, setTarefas] = React.useState([]);
const [novaTarefa, setNovaTarefa] = React.useState("");
const adicionarTarefa = () => {
setTarefas([...tarefas, { id: Date.now(), texto: novaTarefa, concluida: false }]);
setNovaTarefa("");
};
const alternarTarefa = (id) => {
setTarefas(tarefas.map(t =>
t.id === id ? { ...t, concluida: !t.concluida } : t
));
};
return (
<div>
<input value={novaTarefa} onChange={e => setNovaTarefa(e.target.value)} />
<button onClick={adicionarTarefa}>Adicionar</button>
<ul>
{tarefas.map(t => (
<li key={t.id} onClick={() => alternarTarefa(t.id)}>
{t.texto} - {t.concluida ? "✓" : "✗"}
</li>
))}
</ul>
</div>
);
}
Passagem de props dinâmicas para componentes filhos:
function Tabela({ dados, colunas, ...propsTabela }) {
return (
<table {...propsTabela}>
<thead>
<tr>
{colunas.map(col => <th key={col}>{col}</th>)}
</tr>
</thead>
<tbody>
{dados.map((linha, i) => (
<tr key={i}>
{colunas.map(col => <td key={col}>{linha[col]}</td>)}
</tr>
))}
</tbody>
</table>
);
}
// Uso
<Tabela
dados={usuarios}
colunas={["nome", "email"]}
className="tabela-azul"
id="tabela-usuarios"
/>
7. Combinações Avançadas e Boas Práticas
Uso simultâneo dos três operadores:
function configurarServidor(
porta = 3000,
host = "localhost",
...middlewares
) {
const config = {
porta,
host,
middlewares: middlewares.length > 0 ? middlewares : [loggerMiddleware()]
};
return {
...config,
url: `http://${host}:${porta}`,
iniciar: () => console.log(`Servidor rodando em ${config.url}`)
};
}
const servidor = configurarServidor(
8080,
"0.0.0.0",
authMiddleware,
corsMiddleware
);
Imutabilidade e efeitos colaterais:
// Ruim: mutação direta
function atualizarUsuario(usuario, novosDados) {
usuario.nome = novosDados.nome; // Mutação!
return usuario;
}
// Bom: imutabilidade com spread
function atualizarUsuario(usuario, novosDados) {
return { ...usuario, ...novosDados };
}
Armadilhas comuns: spread realiza cópia rasa (shallow copy)
const obj = { a: 1, b: { c: 2 } };
const copia = { ...obj };
copia.b.c = 99; // Modifica o original também!
console.log(obj.b.c); // 99
// Para deep copy, use structuredClone ou bibliotecas
const copiaProfunda = structuredClone(obj);
8. Exemplos Integrados JavaScript + Node.js + React
Função utilitária compartilhada entre frontend e backend:
// shared/utils.js
export function criarQueryString(base = {}, ...parametros) {
const params = parametros.reduce((acc, p) => ({ ...acc, ...p }), {});
const query = { ...base, ...params };
return Object.entries(query)
.filter(([_, v]) => v !== undefined && v !== null)
.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
.join("&");
}
Componente React consumindo API Node.js com parâmetros dinâmicos:
function useApi(endpoint, ...parametrosExtras) {
const [dados, setDados] = React.useState(null);
const [carregando, setCarregando] = React.useState(true);
React.useEffect(() => {
const buscarDados = async () => {
const query = criarQueryString(
{ limite: 10, pagina: 1 },
...parametrosExtras
);
const resposta = await fetch(`/api/${endpoint}?${query}`);
const resultado = await resposta.json();
setDados(resultado);
setCarregando(false);
};
buscarDados();
}, [endpoint, ...parametrosExtras]);
return { dados, carregando };
}
// Uso no componente
function ListaUsuarios() {
const { dados, carregando } = useApi("usuarios", { ativo: true }, { cargo: "admin" });
if (carregando) return <div>Carregando...</div>;
return <pre>{JSON.stringify(dados, null, 2)}</pre>;
}
Refatoração de código legado usando operadores modernos:
// Código legado
function criarUsuario(nome, idade, email, telefone, endereco) {
return {
nome: nome || "Anônimo",
idade: idade || 0,
email: email || "sem@email.com",
telefone: telefone || "não informado",
endereco: endereco || {}
};
}
// Refatorado com parâmetros padrão, rest e spread
function criarUsuario(
nome = "Anônimo",
idade = 0,
...outros
) {
const [email = "sem@email.com", telefone = "não informado", endereco = {}] = outros;
return {
nome,
idade,
email,
telefone,
...endereco,
contato: { email, telefone }
};
}
Referências
-
MDN Web Docs: Default parameters — Documentação oficial sobre parâmetros padrão em funções JavaScript, com exemplos detalhados e casos de uso.
-
MDN Web Docs: Rest parameters — Guia completo sobre o operador rest, incluindo diferenças do objeto arguments e exemplos práticos.
-
MDN Web Docs: Spread syntax — Documentação oficial sobre a sintaxe spread para arrays e objetos, com exemplos de clonagem e mesclagem.
-
React Documentation: Updating Objects in State — Guia oficial do React sobre como usar o spread operator para atualizar estados de forma imutável.
-
Node.js Documentation: Express Middleware — Documentação oficial do Express sobre criação de middlewares, onde parâmetros padrão e rest são frequentemente utilizados.
-
JavaScript.info: Rest parameters and spread syntax — Tutorial completo e interativo sobre rest parameters e spread operator, com exemplos práticos e exercícios.
-
W3Schools: JavaScript Function Parameters — Tutorial introdutório sobre parâmetros de funções em JavaScript, incluindo valores padrão e rest parameters.