Objetos Literais: Uma Alternativa aos Switch Statements em JavaScript

Em JavaScript, frequentemente nos deparamos com múltiplos caminhos para resolver o mesmo problema. Uma situação comum é implementar lógicas condicionais baseadas em diferentes valores. A abordagem clássica é usar a declaração switch, mas existe uma solução mais elegante que utiliza Object literals JavaScript, que considero mais limpa e fácil de manter em muitas situações.

A clássica declaração switch

Primeiro, vamos relembrar como uma declaração switch típica se parece:

“`javascript
const getAnimalSound = animal => {
switch (animal) {
case ‘dog’:
return ‘woof’;
case ‘cat’:
return ‘meow’;
case ‘cow’:
return ‘moo’;
case ‘fox’:
return ‘what does the fox say?’;
default:
return ‘unknown sound’;
}
};

console.log(getAnimalSound(‘dog’)); // ‘woof’
console.log(getAnimalSound(‘fox’)); // ‘what does the fox say?’
console.log(getAnimalSound(‘tiger’)); // ‘unknown sound’
“`

Embora funcione bem, essa abordagem é bastante verbosa e exige muitas declarações case e break (embora tenhamos evitado os breaks aqui usando return), e não é muito DRY (Don’t Repeat Yourself, ou Não Se Repita).

Alternativa com Object literals JavaScript

Vamos refatorar a função acima usando um object literal:

“`javascript
const getAnimalSound = animal => {
const sounds = {
dog: ‘woof’,
cat: ‘meow’,
cow: ‘moo’,
fox: ‘what does the fox say?’,
default: ‘unknown sound’
};

return sounds[animal] || sounds.default;
};

console.log(getAnimalSound(‘dog’)); // ‘woof’
console.log(getAnimalSound(‘fox’)); // ‘what does the fox say?’
console.log(getAnimalSound(‘tiger’)); // ‘unknown sound’
“`

O resultado é o mesmo, mas veja como o código ficou mais limpo e conciso! Definimos um objeto onde cada chave é um valor potencial do nosso parâmetro animal, e cada valor é o som correspondente.

Em seguida, usamos o parâmetro para acessar a propriedade correspondente em nosso objeto. O operador || fornece um fallback caso a propriedade não exista (assim como o nosso case default no switch).

Indo além com funções

Object literals realmente brilham quando você precisa fazer mais do que apenas retornar um valor simples. Digamos que temos um exemplo mais complexo onde precisamos realizar diferentes operações com base em um comando:

“`javascript
const executeCommand = command => {
switch (command) {
case ‘greet’:
console.log(‘Hello there!’);
break;
case ‘farewell’:
console.log(‘Goodbye!’);
break;
case ‘time’:
console.log(`Current time: ${new Date().toLocaleTimeString()}`);
break;
default:
console.log(‘Unknown command’);
}
};

executeCommand(‘greet’); // ‘Hello there!’
executeCommand(‘time’); // ‘Current time: 12:34:56’
“`

Podemos refatorar isso usando um object literal com funções como valores:

“`javascript
const executeCommand = command => {
const commands = {
greet: () => console.log(‘Hello there!’),
farewell: () => console.log(‘Goodbye!’),
time: () => console.log(`Current time: ${new Date().toLocaleTimeString()}`),
default: () => console.log(‘Unknown command’)
};

// Execute o comando se ele existir, caso contrário, execute o comando padrão
(commands[command] || commands.default)();
};

executeCommand(‘greet’); // ‘Hello there!’
executeCommand(‘time’); // ‘Current time: 12:34:56’
“`

Novamente, reduzimos a verbosidade e tornamos o código mais fácil de manter. Cada comando está claramente associado à sua implementação, e não há necessidade de declarações break.

Exemplos mais complexos

Você também pode lidar com casos mais complexos, onde pode ser necessário acessar o contexto ou passar parâmetros para as funções:

“`javascript
const calculator = (a, b, operation) => {
const operations = {
add: (x, y) => x + y,
subtract: (x, y) => x – y,
multiply: (x, y) => x * y,
divide: (x, y) => y !== 0 ? x / y : ‘Cannot divide by zero’,
default: () => ‘Unknown operation’
};

return (operations[operation] || operations.default)(a, b);
};

console.log(calculator(5, 3, ‘add’)); // 8
console.log(calculator(5, 3, ‘multiply’)); // 15
console.log(calculator(5, 0, ‘divide’)); // ‘Cannot divide by zero’
console.log(calculator(5, 3, ‘power’)); // ‘Unknown operation’
“`

Nesse caso, estamos passando os parâmetros a e b para qualquer função de operação que seja selecionada.

Quando usar Object literals vs switch

Embora object literals ofereçam uma sintaxe mais limpa em muitos casos, existem situações em que uma declaração switch ainda pode ser preferível:

1. Quando suas condições de case não são correspondências simples (por exemplo, envolvem intervalos ou expressões complexas).
2. Quando você precisa “passar por” vários cases intencionalmente.
3. Quando seus cases precisam acessar variáveis no escopo circundante.

Mas para mapeamento simples entre entradas e saídas ou ações, object literals geralmente fornecem uma solução mais elegante.

Um exemplo prático do mundo real

Digamos que você esteja construindo uma máquina de estado simples para um componente de UI, onde você precisa lidar com diferentes ações com base no estado atual:

“`javascript
const handleStateTransition = (currentState, action) => {
const stateTransitions = {
idle: {
start: ‘loading’,
reset: ‘idle’
},
loading: {
success: ‘loaded’,
error: ‘error’,
cancel: ‘idle’
},
loaded: {
refresh: ‘loading’,
clear: ‘idle’
},
error: {
retry: ‘loading’,
clear: ‘idle’
}
};

return stateTransitions[currentState]?.[action] || currentState;
};

let state = ‘idle’;
state = handleStateTransition(state, ‘start’); // ‘loading’
state = handleStateTransition(state, ‘success’); // ‘loaded’
state = handleStateTransition(state, ‘clear’); // ‘idle’
state = handleStateTransition(state, ‘invalidAction’); // ‘idle’ (unchanged)
“`

Essa implementação é muito mais limpa do que uma declaração switch massiva com condições aninhadas e torna a lógica da máquina de estado muito clara e fácil de modificar.

Usar Object literals JavaScript oferece uma alternativa poderosa às declarações switch, proporcionando diversas vantagens:

1. Código mais conciso e legível.
2. Melhor desempenho em muitos casos (navegadores podem otimizar pesquisas de objetos).
3. Mais fácil de manter e estender.
4. Não há necessidade de declarações break ou se preocupar com o comportamento de fall-through.

Na próxima vez que você se vir usando uma declaração switch, considere se um object literal pode tornar seu código mais limpo e fácil de manter. É uma técnica simples, mas eficaz, que uso frequentemente em meus projetos JavaScript.

Este conteúdo foi auxiliado por Inteligência Artificial, mas escrito e revisado por um humano.

Via dev.to

Leave a Comment