Neste artigo aprenderemos como emular em Javascript parâmetros nomeados através da atribuição via desestruturação (destructuring assignment).

O problema

Não é raro desenvolvedores procurarem entender um código lendo-o diretamente em vez de consultar sua documentação. O código nunca mente, ou ele funciona ou não funciona, já uma documentação pode ser incompleta ou até mesmo desatualizada. Nesse sentido, facilitar a leitura é importante não só para terceiros, mas também para quem desenvolve o código.

Vejamos o trecho de um código que chama a função moveFrame:

// código anterior omitido 

moveFrame ('sprite1', 'sprite2');

// código posterior omitido 

Para quem lê o código não fica claro o papel de cada parâmetro passado para a função, sendo necessário recorrer à sua declaração. Vejamos:

const moveFrame = (from, to) => {
    /*
        Acessa o elemento do DOM
        removendo e adicionando classes
    */
    console.log(from);
    console.log(to);
};

Agora sabemos que o primeiro parâmetro é o frame de origem e o segundo o frame final.

Uma maneira de tentarmos deixar mais claro a natureza desses dois parâmetros é alterando o nome da função, por exemplo, para moveFrameFromTo. Com essa mudança, o programador que se deparar com a chamada da função, com um pouquinho de esforço, poderá inferir o papel de cada parâmetro passado.

Todavia, tal artifício não seria necessário se o JavaScript suportasse parâmetros nomeados como na linguagem Python.

Python como inspiração

Vejamos o mesmo exemplo na linguagem Python:

def move_frame (from, to):
    # faz alguma coisa com os parâmetros
# chamando a função
move_frame (from="sprite1", to="sprite2")

Para quem lê a chamada da função, fica evidente que “sprite1” se refere ao parâmetro from e “sprite2” ao parâmetro to. Isso evitará que ela tenha que consultar a definição da função para saber o contexto de cada parâmetro. Ainda há mais uma vantagem nessa abordagem.

Se a ordem dos parâmetros nomeados da função for invertida, ela continuará com o comportamento esperado. Em suma, não precisamos nos preocupar com a ordem dos parâmetros:

# chamando a função com a posição dos parâmetros invertida
move_frame (to="sprite2", from="sprite1")

Mesmo com parâmetros nomeados, o desenvolvedor que nunca trabalhou com a função ou não lembra dos seus parâmetros precisará consultá-la para verificar os parâmetros suportados. No entanto, isso não invalida a melhora na legibilidade do código e a vantagem de não precisarmos passar os parâmetros em uma ordem específica.

Será que conseguimos aplicar essa mesma estratégia em nosso código Javascript, mesmo ela não suportando parâmetros nomeados? É o que veremos a seguir.

Primeira tentativa. Recebendo um objeto como parâmetro

Vamos alterar primeiro a chamada da função moveFrame. Ela receberá um objeto JavaScript cuja as propriedades são os parâmetros que precisa receber:

moveFrame ({ from: 'sprite1', to: 'sprite2' });

Excelente, mas do jeito que esta, nossa função moveFrame precisará receber um objeto JavaScript. Um desvantagem dessa abordagem é não sabermos identificar rapidamente quais são as propriedades do objeto recebido que serão consideradas “parâmetros” da função. Por fim, se estivermos modificando um código já existente seremos obrigados a mudar o acesso às variáveis from e to para parameters.from e parameters.to respectivamente:

/*
    Ok, recebemos "parameters", um objeto. Mas quais 
    são as chaves que usaremos como parâmetro?
*/
const moveFrame = parameters => {

   /* 
    Seremos obrigados a acessar 
    as proprieades do objeto
   */
   console.log(parameters.from);
   console.log(parameters.to);
};

Mas nem tudo esta perdido. A boa notícia é que podemos conseguir um resultado parecido com o que vimos na linguagem Python emulando parâmetros nomeados através de destructuring assignment.

Emulando parâmetros nomeados através de destructuring assignment

Vamos alterar o parâmetro de moveFrame. Ele ficará assim:

const moveFrame = ({ from, to }) => {
   /*
    Mudamos o parâmetro, mas o restante do código 
    continou como estava
   */
   console.log(from);
   console.log(to);
};

A nossa chamada passando um objeto como parâmetro continua funcionando:

moveFrame ({ from: 'sprite1', to: 'sprite2' });

Perfeito! Utilizamos as chaves de um objeto para nomear os parâmetros recebidos pela função e através de destructuring assignment tratamos cada propriedade como variável dentro da função. Podemos até inverter a ordem das propriedades sem impactar em nosso código:

moveFrame ({ to: 'sprite2', from: 'sprite1' });

Para que o leitor perceba com mais clareza o que esta contecendo por debaixo dos panos, segue um exemplo de escopo menor:

const parameters = {
    from: 'sprite1',
    to: 'sprite2', 
};
// atribuição via desestruturaçãp
const { from, to } = parameters;
// imprime "sprite1"
console.log(from);
// imprime "sprite2"
console.log(to);

O interpretador cria as variáveis from e to com base nas propriedades do objeto!

Conclusão

Tomar como inspiração o que há de melhor em outras linguagens e tentar aplicá-lo em sua linguagem é praticar a sabedoria do programador.

E você? Já utilizava essa estratégia antes? Há recursos de outras linguagens que você gostaria que existisse em JavaScript? Deixe sua opinião.