JavaScript — Brincando com Arrays

Hoje estava brincando de criar alguns Arrays e pensei em criar um padrão de Estrutura de Dados para isso.


Ideia

Criar um mecanismo para geração de Arrays de forma modular e atômica.

Para isso precisamos separar a criação do Array com um tamanho definido da criação dos elementos que irão fazer parte dela.

Por exemplo:

Crie um Array apenas com Números Ímpares de tamanho dez .
Crie um Array de tamanho dez apenas com Números Ímpares.

Desenvolvimento

Inicialmente vamos analisar como criamos um Array utilizando o from para que possamos definir quais valores e qual o tamanho do Array:

Utilizando o Array.from nós conseguimos definir, separadamente, o tamanho e como serão criados os seus elementos, entretanto, perceba que essa função ainda pode ser melhorada, ficando mais modular e re-usável.

Vamos pensar o seguinte:

Qual parâmetro é o mais importante? A função que irá definir quais valores eu terei ou seu tamanho?

Vamos ver os dois exemplos para isso:

Agora eu lhe pergunto:

Você prefere definir a criação dos seus Arrays baseando-se nos seus elementos ou no seu tamanho?

Eu prefiro definir pelos seus elementos e deixar o tamanho como função final, a função que concretizará a criação do Array, pois é mais fácil eu reusar uma função que gera Arrays de Números Pares do que uma função que gera Arrays apenas com um tamanho fixo.

Não concorda?

Padrão

Então esse será nosso padrão inicial:

Com isso podemos criar as funções de geração dos elementos separadamente, podendo assim encapsular diferentes sequências:

Todavia, se você quiser gerar Arrays com apenas um valor repetido também pode usar a seguinte solução:

Entretanto você não conseguirá gerar, por exemplo, Arrays de Números Pares e Ímpares, como podemos ver abaixo com a solução anterior:


Fluent Interface

Depois disso peguei me indagando como eu poderia fazer um encadeamento dessas funções para que após a definição dos elementos eu chamasse a função que define o tamanho e retorne o Array desejado.

Isso me fez lembrar de um conceito chamado: Fluent Interface.

Veja o que diz a Wikipedia:

In software engineering, a fluent interface (as first coined by Eric Evans and Martin Fowler) is a method for constructing object oriented APIs, where the readability of the source code is close to that of ordinary written prose.
A fluent interface is normally implemented by using method chaining to relay the instruction context of a subsequent call (but a fluent interface entails more than just method chaining [1]).

fonte: Fluent interface — Wikipedia

Vamos imaginar que queremos utilizar nossa função assim:

createArrayWith( odds ).withSize( 10 )

Para isso acontecer teremos que fazer uma malandragem da grossa!


withSize

E se eu quiser modificar essa função para que eu pudesse encadear outro função onde eu passaria o tamanho do Array?

Peguei-me pensando nisso e a solução que achei foi a seguinte:

Note bem como fiz a criação dessa Closure, não retornei apenas uma função anônima, mas sim um Objeto que contém a função nomeada withSize , a qual é o retorno da primeira aplicação/execução da createArray . Por isso eu passei como parâmetro a função geradora, para que ela pudesse ser executada posteriormente pela withSize .


get

Vamos viajar um pouco mais e imaginar que queremos, após a geração do Array, pegar apenas um elemento ou uma faixa de elementos.

Deixei por hora como get , pois logo mais eu renomeei para take :

Com certeza você deve ter achado um pouco estranha essa função get . Por isso irei destrinchar ela para você, vamos lá:

Primeiramente você deve entender que o Array arr seria o nosso resultado final sem termos a função get , por isso eu crio ele e já injeto no get através da IIFE, como eu estou executando ela, a função que será definida em get é a função que espera o parâmetro ...pos que será a posição ou a faixa de posições que iremos querer como resultado.

Utilizei o Rest Parameter para que o valor de pos sempre vire um Array, por exemplo:

Os comentários são os valores após o ...pos , ou seja, quando você não passa nenhum valor ele é vazio, por isso que quando testo se pos.length === 1 ele só irá pegar o caso quando definimos apenas uma posição desejada, caindo em ? arr[ pos ] . Caso seja diferente de 1 então cairá no arr.slice , então se eu não passar nenhum valor o retorno será o Array inteiro, se não será o pedaço definido do slice.

Logicamente você sabe que o slice aceita apenas 2 valores (início e fim) separados por vírgula, por isso mesmo utilizamos arr.slice( ...pos ) . Para que após a conversão anterior em Array você “desconverta” para que consiga passar os valores corretamente.


Refatorando

Vamos dar aquela refatorada marota porque nossa solução estão muito “complexa” em uma primeira olhada, então vamos começar separando a função mais interna: get .

Porém não poderemos utilizar a palavra get fora do nosso Objeto, por isso renomeei para: _get .

Agora é a hora de separar a withSize :

Notou que tivemos que criar ela como uma Closure também pois anteriormente ela só tinha como parâmetro o size , pois a função geradora vinha diretamente na função pai, como retiramos ela do bloco da createArrayWith foi necessário passar essa função de alguma forma.


Funcional

Dessa vez vamos deixar o código um pouco mais simples, porém sem ter o encadeamento das outras funções.

Como sabemos que a função que define o tamanho só pode ser chamada após a definição da sua função geradora, vamos fazer dessa forma:

Agora é a vez da função take , antiga get :

Percebeu que nessa refatorada eu mudei os parâmetros que entrarão nessas funções, passando os dois de uma só vez, para facilitar nossa vida.

E aí qual das duas soluções você preferiu?
Por favor comente abaixo sua escolha.

Conclusão

Brincamos de gerar Arrays tanto com Fluent Interface como da forma mais “Funcional”, utilizando como base a mesma ideia e funções, com pequenas modificações entre uma solução e outra.

Também mostrei algumas malandragens utilizadas para criar a Fluent Interface, que utiliza pesadamente Closures.

Até a próxima em mais uma Viajada do Suissa!
Like what you read? Give Suissa a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.