As 11 principais (e mais!) funções JavaScript obrigatórias

Código inteligente! Seja um desenvolvedor JavaScript mais rápido, produtivo e feliz ao dominar essas funções mais importantes e recorrentes da linguagem.

Seja back-end ou front-end (ou mesmo naves espaciais), o JavaScript está em toda parte. Também é uma linguagem bastante flexível (o que significa que possui padrões de programação funcional hardcore, bem como as boas e velhas classes), e sua semelhança com outras linguagens “tipo C” facilita a transição para desenvolvedores de outras linguagens.

Se você quiser Aumente o nível do seu jogo JS, sugiro que você aprenda, pratique e, eventualmente, domine as seguintes funções principais disponíveis no idioma. Nem todos são estritamente “necessários” para resolver problemas, mas podem fazer muito trabalho pesado para você em alguns casos, enquanto em outros podem reduzir a quantidade de código que você precisa escrever.

mapa()

Seria uma heresia escrever um artigo sobre funções JavaScript importantes e não mencionar map()! 😆😆 Junto com filter() e reduce(), map() forma uma espécie de trindade sagrada. Essas são funções que você usará repetidamente em sua carreira, portanto, vale a pena dar uma olhada. Vamos abordá-los um por um, começando com map().

map() está entre as funções que dão mais problemas para as pessoas aprenderem JavaScript. Por quê? Não porque haja algo inerentemente complexo nisso, mas porque a maneira como essa função funciona é uma ideia tirada do que chamamos de Programação Funcional. E como não estamos expostos à Programação Funcional – nossas escolas e a indústria estão cheias de linguagens orientadas a objetos – o funcionamento parece estranho ou mesmo errado para nossos cérebros tendenciosos.

O JavaScript é muito mais funcional do que o orientado a objetos, embora suas versões modernas estejam fazendo o possível para ocultar esse fato. Mas isso é uma lata de minhocas que posso abrir talvez outro dia. 🤣 Ok, então map() . . .

map() é uma função muito simples; ele se anexa a um array e nos ajuda a converter cada item em outra coisa, resultando em um novo array. Como exatamente converter um item é fornecido como outra função, que por convenção é anônima.

Isso é tudo! A sintaxe pode levar algum tempo para se acostumar, mas essencialmente é isso que estamos fazendo em uma função map(). Por que queremos usar map ()? Depende do que estamos tentando alcançar. Por exemplo, digamos que registramos a temperatura de cada dia da última semana e a armazenamos como um array simples. No entanto, agora somos informados de que os instrumentos não eram muito precisos e relataram 1,5 graus a menos de temperatura do que deveriam.

Podemos fazer essa correção usando a função map() assim:

const weeklyReadings = [20, 22, 20.5, 19, 21, 21.5, 23];

const correctedWeeklyReadings = weeklyReadings.map(reading => reading + 1.5);

console.log(correctedWeeklyReadings); // gives [ 21.5, 23.5, 22, 20.5, 22.5, 23, 24.5 ]

Outro exemplo muito prático vem do mundo do React, onde criar listas de elementos DOM a partir de arrays é um padrão comum; então, algo assim é comum:

export default ({ products }) => {
    return products.map(product => {
        return (
            <div className="product" key={product.id}>
                <div className="p-name">{product.name}</div>
                <div className="p-desc">{product.description}</div>
            </div>
        );
    });
};

Aqui, temos um componente React funcional que recebe uma lista de produtos como props. A partir dessa lista (matriz), ele cria uma lista de “divs” HTML, essencialmente convertendo cada objeto de produto em HTML. O objeto de produtos originais permanece intocado.

Você pode argumentar que map () não é nada além de um loop for glorificado e você estaria totalmente certo. Mas observe que assim que você faz esse argumento, é sua mente treinada orientada a objetos que está falando, enquanto essas funções e sua lógica vêm da Programação Funcional, onde uniformidade, compacidade e elegância são altamente reverenciadas. 🙂

filtro()

filter() é uma função altamente útil que você se verá aplicando repetidas vezes em muitas situações. Como o nome sugere, essa função filtra uma matriz com base nas regras/lógica que você fornece e retorna uma nova matriz contendo itens que atendem a essas regras.

Vamos reutilizar nosso exemplo de clima. Suponha que temos um array contendo as temperaturas máximas para cada dia da última semana; agora, queremos descobrir quantos desses dias foram mais frios. Sim, “mais frio” é um termo subjetivo, então digamos que estamos procurando dias em que a temperatura esteja abaixo de 20. Podemos fazer isso usando a função filter() assim:

const weeklyReadings = [20, 22, 20.5, 19, 21, 21.5, 23];

const colderDays = weeklyReadings.filter(dayTemperature => {
    return dayTemperature < 20;
});

console.log("Total colder days in week were: " + colderDays.length); // 1

Observe que a função anônima que passamos para filter() deve retornar um valor booleano: true ou false. É assim que o filter() saberá se deve ou não incluir aquele item no array filtrado. Você é livre para escrever qualquer quantidade de lógica complexa dentro dessa função anônima; você pode fazer chamadas de API e ler as entradas do usuário e assim por diante, desde que tenha certeza de que, no final, está retornando um valor booleano.

Cuidado: esta é uma nota lateral que me sinto compelido a fornecer com base em minha experiência como desenvolvedor de JavaScript. Seja devido a desleixo ou fundamentos errados, muitos programadores criam bugs sutis em seus programas ao usar filter(). Vamos reescrever o código anterior para conter o bug:

const weeklyReadings = [20, 22, 20.5, 19, 21, 21.5, 23];

const colderDays = weeklyReadings.filter(dayTemperature => {
    return dayTemperature < 20;
});

if(colderDays) {
    console.log("Yes, there were colder days last week");
} else {
    console.log("No, there were no colder days");
}

Observe algo? Ótimo trabalho se você fez! A condição if no final verifica colderDays, que na verdade é um array! Você ficará surpreso com quantas vezes as pessoas cometem esse erro enquanto correm para cumprir prazos ou codificar desanimadas (por qualquer motivo). O problema com essa condição é que o JavaScript é uma linguagem estranha e inconsistente de várias maneiras, e a “veracidade” das coisas é uma delas. Enquanto [] == true retorna false, fazendo você pensar que o código acima não está quebrado, a realidade é que dentro de uma condição if, [] avalia como verdadeiro! Em outras palavras, o código que escrevemos nunca dirá que não houve dias mais frios na semana passada.

  Splashtop é uma alternativa viável para a área de trabalho remota da Microsoft?

A correção é muito simples, conforme fornecido no código anterior ao código acima. Verificamos colderDays.length, que com certeza nos fornecerá um número inteiro (zero ou superior) e, portanto, funcionamos consistentemente em comparações lógicas. Observe que filter() sempre, sempre, sempre retornará uma matriz, vazia ou não vazia, portanto, podemos confiar nisso e escrever nossas comparações lógicas com confiança.

Tem sido um desvio mais longo do que eu planejava, mas bugs como este valem a pena destacar em dez mil palavras, tudo em maiúsculas, se necessário. Espero que você não seja mordido por isso e economize centenas de horas de esforço de depuração! 🙂

reduzir()

De todas as funções neste artigo, bem como na biblioteca JavaScript padrão, a reduce() está entre as pioneiras para as coroas de “confuso e estranho”. Embora essa função seja altamente importante e resulte em um código elegante em muitas situações, ela é evitada pela maioria dos desenvolvedores de JavaScript e eles preferem escrever um código mais detalhado.

A razão é que – e vou ser honesto aqui! — reduce() é difícil de entender, tanto no sentido de conceito quanto de execução. Ao ler sua descrição, você a releu várias vezes e, ainda assim, duvida de si mesmo se leu errado; e quando você o vê em ação e tenta visualizar como está funcionando, seu cérebro dá mil nós! 🤭

Agora, não fique com medo. A função reduce() não chega nem perto em complexidade e intimidação de, digamos, Árvores B+ e seus algoritmos. Acontece que esse tipo de lógica raramente é encontrado durante o dia de trabalho do programador comum.

Então, tendo assustado você e imediatamente dizendo para você não se preocupar, eu finalmente gostaria de mostrar a você o que é essa função e por que exatamente podemos precisar dela.

Como o nome sugere, reduce() é usado para, bem, reduzir alguma coisa. O que ele reduz é um array e o que reduz o array dado é um único valor (número, string, função, objeto, o que for). Aqui está uma maneira mais simples de colocar isso — reduce() transforma um array em um único valor. Observe que o valor de retorno de reduce() não é um array, que é o caso de map() e filter(). Ter entendido isso já é metade da batalha. 🙂

Agora, é meio óbvio que se vamos transformar (reduzir) um array, precisamos fornecer a lógica necessária; e com base em sua experiência como desenvolvedor JS, você provavelmente já adivinhou que fazemos isso usando uma função. Essa função é o que chamamos de função redutora, que forma o primeiro argumento para reduce(). O segundo argumento é um valor inicial, como um número, uma string, etc. (explicarei daqui a pouco o que diabos é esse “valor inicial”).

Com base em nosso entendimento até agora, podemos dizer que uma chamada para reduce() se parece com isso: array.reduce(reducerFunction, StartingValue). Agora vamos abordar o coração de tudo: a função redutora. Como já estabelecido, a função redutor é o que diz a reduce() como converter o array em um único valor. São necessários dois argumentos: uma variável para atuar como um acumulador (não se preocupe, também explicarei essa parte) e uma variável para armazenar o valor atual.

Eu sei eu sei . . . era muita terminologia para uma única função que nem é obrigatória em JavaScript. 😝😝 E é por isso que as pessoas fogem do reduce(). Mas se você aprender passo a passo, você não apenas entenderá, mas também a apreciará ao se tornar um desenvolvedor melhor.

Ok, então, de volta ao tópico em questão. O “valor inicial” que está sendo passado para reduce() é . . . bem, o valor inicial para o cálculo que você deseja usar. Por exemplo, se você for fazer uma multiplicação na função redutora, um valor inicial de 1 faz sentido; para adição, você pode começar com 0 e assim por diante.

Agora vamos ver a assinatura da função redutora. Uma função redutora sendo passada para reduce() tem o seguinte formato: reducerFunction(accumulator, currentValue). “Acumulador” é apenas um nome chique para a variável que coleta e armazena o resultado do cálculo; é exatamente como usar uma variável chamada total para somar todos os itens em uma matriz usando algo como total += arr[i]. É exatamente assim que a função redutora em reduce() é aplicada: o acumulador é inicialmente definido para o valor inicial que você fornece e, em seguida, um a um, os elementos da matriz são visitados, o cálculo é executado e o resultado é armazenado em o acumulador, e assim por diante. . .

Então, o que é esse “valor atual” em uma função redutora? É a mesma ideia que você imaginaria mentalmente se eu pedisse para percorrer uma matriz: você pegaria uma variável para começar no índice zero e a moveria para frente um passo de cada vez. Enquanto estiver fazendo isso, se eu pedir para parar de repente, você se encontrará em um dos elementos da matriz, certo? Isso é o que queremos dizer com valor atual: é o valor da variável usada para representar o item do array que está sendo considerado no momento (pense em fazer um loop em um array se isso ajudar).

Com tudo isso dito, é hora de ver um exemplo simples e ver como todo esse jargão se junta em uma chamada de reduce() real. Digamos que temos um array contendo os primeiros n números naturais (1, 2, 3… n) e estamos interessados ​​em encontrar o fatorial de n. Sabemos que para encontrar n! basta multiplicar tudo, o que nos leva a esta implementação:

const numbers = [1, 2, 3, 4, 5];
const factorial = numbers.reduce((acc, item) => acc * item, 1);
console.log(factorial); // 120

Muita coisa está acontecendo nessas meras três linhas de código, então vamos descompactá-las uma a uma no contexto da (muito longa) discussão que tivemos até agora. Como é óbvio, números é a matriz que contém todos os números que queremos multiplicar. Em seguida, dê uma olhada na chamada numbers.reduce(), que diz que o valor inicial para acc deve ser 1 (porque não influencia ou destrói nenhuma multiplicação). Em seguida, verifique o corpo da função redutora, `(acc, item) => acc * item, que simplesmente diz que o valor de retorno para cada iteração no array deve ser aquele item multiplicado pelo que já estiver no acumulador. A iteração e o armazenamento real da multiplicação explicitamente no acumulador é o que está acontecendo nos bastidores e é um dos maiores motivos pelos quais o reduce() é um obstáculo para os desenvolvedores de JavaScript.

  Como excluir sua conta Riot

Por que usar reduz ()?

É uma pergunta muito boa e, para ser honesto, não tenho uma resposta certa. O que quer que reduce() faça pode ser feito através de loops, forEach(), etc. No entanto, essas técnicas resultam em muito mais código, dificultando a leitura, especialmente se você estiver com pressa. Depois, há a preocupação com a imutabilidade: com reduce() e funções semelhantes, você pode ter certeza de que seus dados originais não foram alterados; isso por si só elimina classes inteiras de bugs, especialmente em aplicativos distribuídos.

Por fim, reduce() é muito mais flexível, no sentido de que o acumulador pode ser um objeto, um array ou mesmo uma função, se necessário; o mesmo vale para o valor inicial e outras partes da chamada de função — quase tudo pode entrar e quase tudo pode sair, portanto, há extrema flexibilidade no design de código reutilizável.

Se você ainda não está convencido, tudo bem também; a comunidade JavaScript em si está nitidamente dividida quanto à “compacidade”, “elegância” e “poder” de reduce(), então tudo bem se você não usá-lo. 🙂 Mas certifique-se de olhar para alguns exemplos puros antes de decidir bin reduzir ().

algum()

Digamos que você tenha uma matriz de objetos, com cada objeto representando uma pessoa. Você deseja saber se há pessoas na matriz com mais de 35 anos. Observe que não há necessidade de contar quantas dessas pessoas existem, muito menos recuperar uma lista delas. O que estamos dizendo aqui é o equivalente a “um ou mais” ou “pelo menos um”.

Como você faz isso?

Sim, você pode criar uma variável de sinalizador e percorrer o array para resolver este problema assim:

const persons = [
    {
        name: 'Person 1',
        age: 32
    },
    
    {
        name: 'Person 2',
        age: 40
    },
];

let foundOver35 = false;

for (let i = 0; i < persons.length; i ++) {
    if(persons[i].age > 35) {
        foundOver35 = true;
        break;
    }
}

if(foundOver35) {
    console.log("Yup, there are a few people here!")
}

O problema? O código é muito parecido com C ou Java, na minha opinião. “Verbose” é outra palavra que vem à mente. JS experiente pode estar pensando em “feio”, “horrível”, etc. 😝 E com razão, eu diria. Uma maneira de melhorar esse trecho de código é usar algo como map(), mas mesmo assim a solução é um pouco desajeitada.

Acontece que temos uma função bastante interessante chamada some() já disponível na linguagem principal. Essa função trabalha com arrays e aceita uma função de “filtragem” customizada, retornando um valor booleano verdadeiro ou falso. Essencialmente, é fazer o que tentamos fazer nos últimos minutos, mas de forma muito sucinta e elegante. Veja como podemos usá-lo:

const persons = [
    {
        name: 'Person 1',
        age: 32
    },
    
    {
        name: 'Person 2',
        age: 40
    },
];

if(persons.some(person => {
    return person.age > 35
})) {
    console.log("Found some people!")
}

Mesma entrada, o mesmo resultado de antes; mas observe a enorme redução no código! Observe também como a carga cognitiva é drasticamente reduzida porque não precisamos mais analisar o código linha por linha como se nós mesmos fôssemos o intérprete! O código agora quase parece uma linguagem natural.

todo()

Assim como some(), temos outra função útil chamada every(). Como você pode imaginar agora, isso também retorna um valor booleano, dependendo se todos os itens da matriz passam no teste fornecido. Obviamente, o teste a ser aprovado é fornecido como uma função anônima na maioria das vezes. Vou poupá-lo da dor de como uma versão ingênua do código pode parecer, então veja como every() é usado:

const entries = [
    {
        id: 1
    },
    
    {
        id: 2
    },
    
    {
        id: 3  
    },
];

if(entries.every(entry => {
    return Number.isInteger(entry.id) && entry.id > 0;
})) {
    console.log("All the entries have a valid id")
}

Como é óbvio, o código verifica todos os objetos na matriz em busca de uma propriedade id válida. A definição de “válido” depende do contexto do problema, mas como você pode ver, para este código, considerei inteiros não negativos. Mais uma vez, vemos como o código é simples e elegante de ler, que é o único objetivo desta(s) função(ões) (e similares).

inclui()

Como você verifica a existência de substrings e elementos de array? Bem, se você for como eu, procure rapidamente indexOf() e, em seguida, consulte os documentos para saber seus possíveis valores de retorno. É uma inconveniência considerável e os valores de retorno são difíceis de lembrar (rápido — o que significa um processo que retorna 2 para o sistema operacional?).

Mas há uma boa alternativa que podemos usar: includes(). O uso é tão simples quanto o nome, e o código resultante é extremamente emocionante. Lembre-se de que a correspondência é feita por includes () e diferencia maiúsculas de minúsculas, mas acho que é o que todos esperamos intuitivamente. E agora, hora de algum código!

const numbers = [1, 2, 3, 4, 5];
console.log(numbers.includes(4));
const name = "Ankush";
console.log(name.includes('ank')); // false, because first letter is in small caps
console.log(name.includes('Ank')); // true, as expected

No entanto, não espere muito deste método humilde:

const user = {a: 10, b: 20};
console.log(user.includes('a')); // blows up, as objects don't have a "includes" method

Ele não pode olhar dentro de objetos, pois simplesmente não é definido para objetos. Mas ei, sabemos que funciona em arrays, então talvez possamos fazer alguns truques aqui. . . 🤔.

const persons = [{name: 'Phil'}, {name: 'Jane'}];
persons.includes({name: 'Phil'});

Então, o que acontece quando você executa esse código? Não explode, mas o resultado também é decepcionante: falso. 😫😫 Na verdade, isso tem a ver com objetos, ponteiros e como o JavaScript vê e gerencia a memória, que é um mundo à parte. Se você deseja mergulhar mais fundo, sinta-se à vontade para mergulhar (talvez comece aqui), mas vou parar por aqui.

Podemos fazer o código acima se comportar se o reescrevermos da seguinte maneira, mas neste ponto, ele se torna mais ou menos uma piada, na minha opinião:

const phil = {name: 'Phil'};
const persons = [phil, {name: 'Jane'}];
persons.includes(phil); // true

Ainda assim, mostra que podemos fazer includes() funcionar em objetos, então acho que não é um desastre total. 😄

fatiar()

Suponha que temos uma string e peço que você retorne uma parte dela que comece com “r” e termine com “z” (os caracteres reais não são importantes). Como você abordaria isso? Talvez você crie uma nova string e a use para armazenar todos os caracteres necessários e retorná-los. Ou se você for como a maioria dos programadores, você me daria dois índices de array em troca: um indicando o início da substring, o outro marcando o fim.

  Como converter um arquivo CSV para VCF para transferir contatos

Ambas as abordagens são boas, mas existe um conceito chamado fatiamento que oferece uma solução simples em tais situações. Felizmente, não há nenhuma teoria obscura a seguir; fatiar significa exatamente o que parece – criar uma string/matriz menor a partir de uma determinada, assim como criamos fatias de frutas. Vejamos o que quero dizer, com a ajuda de um exemplo simples:

const headline = "And in tonight's special, the guest we've all been waiting for!";
const startIndex = headline.indexOf('guest');
const endIndex = headline.indexOf('waiting');
const newHeadline = headline.slice(startIndex, endIndex);
console.log(newHeadline); // guest we've all been

Quando slice(), fornecemos dois índices para JavaScript — aquele em que queremos iniciar o corte e o outro em que queremos que ele pare. O problema com slice() é que o índice final não está incluído no resultado final, e é por isso que vemos que a palavra “waiting” está faltando no novo título do código acima.

Conceitos como fatiamento são mais proeminentes em outras linguagens, principalmente Python. Se você perguntar a esses desenvolvedores, eles dirão que não conseguem imaginar a vida sem essa funcionalidade, e com razão quando a linguagem fornece uma sintaxe muito boa para fatiar.

Fatiar é simples e extremamente conveniente, e não há razão para não usá-lo. Também não é um açúcar de sintaxe repleto de uma penalidade de desempenho, pois cria cópias superficiais do array/string original. Para desenvolvedores de JavaScript, eu recomendo fortemente familiarizar-se com slice() e adicioná-lo ao seu arsenal!

emenda()

O método splice() soa como um primo de slice() e, de certa forma, podemos argumentar que é. Ambos criam novos arrays/strings a partir dos originais, com uma pequena mas importante diferença — splice() remove, altera ou adiciona elementos, mas modifica o array original. Essa “destruição” do array original pode criar grandes problemas se você não for cuidadoso ou não entender cópias e referências profundas. Eu me pergunto o que impediu os desenvolvedores de usar a mesma abordagem de slice () e deixar a matriz original intocada, mas acho que podemos ser mais indulgentes com uma linguagem criado em apenas dez dias.

Apesar de minhas reclamações, vamos dar uma olhada em como splice() funciona. Vou mostrar um exemplo onde removemos alguns elementos de um array, pois este é o uso mais comum que você encontrará para este método. Também vou me abster de fornecer exemplos de adição e inserção porque eles podem ser facilmente pesquisados ​​e também são simples.

const items = ['eggs', 'milk', 'cheese', 'bread', 'butter'];
items.splice(2, 1);
console.log(items); // [ 'eggs', 'milk', 'bread', 'butter' ]

A chamada para splice() acima diz: comece no índice 2 (ou seja, o terceiro lugar) do array e remova um item. Na matriz fornecida, ‘cheese’ é o terceiro item, portanto, ele é removido da matriz e a matriz de itens é reduzida, conforme esperado. A propósito, os itens removidos são retornados por splice() no formulário ou em uma matriz, portanto, se quiséssemos, poderíamos ter capturado ‘cheese’ em uma variável.

Na minha experiência, indexOf() e splice() têm uma grande sinergia — encontramos o índice de um item e o removemos do array fornecido. No entanto, observe que nem sempre é o método mais eficiente e, geralmente, usar chaves de objeto (o equivalente a um mapa de hash) é muito mais rápido.

mudança()

shift() é um tipo de método de conveniência e é usado para remover o primeiro elemento de uma matriz. Observe que a mesma coisa pode ser feita com splice(), mas shift() é um pouco mais fácil de lembrar e intuitivo quando tudo o que você precisa fazer é cortar o primeiro elemento.

const items = ['eggs', 'milk', 'cheese', 'bread', 'butter'];
items.shift()
console.log(items); // [ 'milk', 'cheese', 'bread', 'butter' ]

unshift()

Assim como shift() remove o primeiro elemento de um array, unshift() adiciona um novo elemento ao início do array. A sua utilização é igualmente simples e compacta:

const items = ['eggs', 'milk'];
items.unshift('bread')
console.log(items); // [ 'bread', 'eggs', 'milk' ]

Dito isso, não posso deixar de avisar os novos no jogo: ao contrário dos métodos populares push() e pop(), shift() e unshift() são extremamente ineficientes (devido à maneira como os algoritmos subjacentes funcionam). Portanto, se você estiver operando em grandes arrays (digamos, mais de 2.000 itens), muitas dessas chamadas de função podem interromper seu aplicativo.

encher()

Às vezes, você precisa alterar vários itens para um único valor ou até mesmo “redefinir” todo o array, por assim dizer. Nessas situações, fill() salva você de loops e erros off-by-one. Ele pode ser usado para substituir parte ou toda a matriz pelo valor fornecido. Vejamos alguns exemplos:

const heights = [1, 2, 4, 5, 6, 7, 1, 1];
heights.fill(0);
console.log(heights); // [0, 0, 0, 0, 0, 0, 0, 0]

const heights2 = [1, 2, 4, 5, 6, 7, 1, 1];
heights2.fill(0, 4);
console.log(heights2); // [1, 2, 4, 5, 0, 0, 0, 0]

Outras funções que merecem destaque

Embora a lista acima seja o que a maioria dos desenvolvedores de JavaScript acaba encontrando e usando em suas carreiras, ela não está completa. Há tantas outras funções (métodos) menores, mas úteis, em JavaScript que não será possível cobri-las todas em um único artigo. Dito isso, alguns que vêm à mente são os seguintes:

  • marcha ré()
  • ordenar()
  • entradas()
  • encher()
  • achar()
  • apartamento()

Eu encorajo você a pelo menos procurá-los para que você tenha uma ideia de que existem conveniências como essas.

Conclusão

JavaScript é uma linguagem grande, apesar do pequeno número de conceitos básicos a serem aprendidos. As muitas funções (métodos) disponíveis para nós compõem a maior parte desse tamanho grande. No entanto, como o JavaScript é uma linguagem secundária para a maioria dos desenvolvedores, não nos aprofundamos o suficiente, perdendo muitas funções úteis e bonitas que ele oferece. Na verdade, o mesmo vale para os conceitos de programação funcional, mas isso é assunto para outro dia! 😅

Sempre que puder, passe algum tempo explorando a linguagem principal (e, se possível, bibliotecas de utilitários famosas, como Lodash). Mesmo alguns minutos gastos fazendo esse esforço resultarão em enormes ganhos de produtividade e código muito mais limpo e compacto.