(EJS) Parte 2 - Contando feijões com o JavaScript

Já estamos quase no natal, e eu estou aqui, te mostrando coisas sobre o livro Eloquent JavaScript 3rd. Hoje vamos ver apenas sobre o capítulo 3, que fala sobre funções e passar por uns exercícios.

O capítulo seguinte sobre estruturas de dados é um pouco extenso, então vamos deixar para o próximo post para não ser tão cansativo.

Definindo funções

Como o autor diz, funções são como pão e manteiga para programadores. E eu concordo com ele.

Vamos ver um exemplo simples de função:

function greet() {
console.log("Hello, world!");
}
greet(); // Hello, world!

Funções também podem receber argumentos, isso é muito útil quando queremos desacoplar a lógica de um código:

function greet(name) {
console.log(`Hello, ${name}!`);
}
greet("John"); // Hello, John!

No JavaScript podemos criar funções de várias formas e irei mostrar algumas delas mais adiante.

Entendendo o escopo

O escopo de uma função é o contexto onde ela foi definida. Isso é muito importante para evitar bugs e problemas de variáveis globais:

let name = "John";
function greet() {
let name = "Doe";
console.log(`Hello, ${name}!`);
}
greet(); // Hello, Doe!

Olhando assim parece simples, mas é muito comum vermos problemas de escopo em códigos grandes e complexos. Por isso é importante entender bem como funciona.

Ainda sobre escopo, podemos ter escopos aninhados sem problemas:

let name = "John";
function greet() {
let name = "Doe";
function sayHello() {
console.log(`Hello, ${name}!`);
}
sayHello(); // Hello, Doe!
}
greet(); // Hello, Doe!

Criando funções de várias formas

Podemos criar funções como valores de variáveis, isso é muito útil para passar funções como argumentos para outras funções:

const greet = function (name) {
console.log(`Hello, ${name}!`);
};
greet("John"); // Hello, John!

Também podemos criar funções de flecha (Arrow Functions), que são mais simples e diretas:

const greet = (name) => {
console.log(`Hello, ${name}!`);
};
greet("John"); // Hello, John!

Funções de auto invocação (IIFE - Immediately Invoked Function Expression) são muito úteis para criar escopos isolados:

(function () {
console.log("Hello, world!");
})();
// Hello, world!

Muito desses conceitos ainda são básicos, mas como eu disse antes esses são os primeiros capítulos e logo logo vamos ver coisas mais interessantes.

Closures e Recursão

As closures são basicamente funções que capturam variáveis do escopo onde foram definidas:

function createCounter() {
let count = 0;
return function () {
count++;
console.log(count);
};
}
const counter = createCounter();
counter(); // 1
counter(); // 2

Recursão é um conceito muito interessante e poderoso, mas deve ser usado com cuidado para não causar um stackoverflow 💩:

function factorial(n) {
if (n === 0) {
return 1;
}
return n * factorial(n - 1);
}
console.log(factorial(5)); // 120

Agora vem os exercícios 🏋️‍♂️

O primeiro é o Minumum que consiste em criar uma função que retorna o menor valor entre dois números, a ideia é fazer na mão mesmo sem usar o operador Math.min:

function minimum(a, b) {
return a < b ? a : b;
}
console.log(minimum(10, 5)); // 5

Bem simples né? Agora bora para o próximo, o Recursion que consiste em criar uma função que verifica se um número é par ou ímpar.

Mas antes o exercício nos dá os seguintes requisitos:

  • Se o número for 0, ele é par.
  • Se o número for 1, ele é ímpar.
  • Para qualquer outro número, você deve subtrair 2 até chegar em 0 ou 1.

O nome da função é isEven e quando conseguir resolver deve testar se funciona com os seguintes números: 50, 75 e -1.

function isEven(n) {
if (n === 0) {
return true;
}
if (n === 1) {
return false;
}
return isEven(n - 2);
}
console.log(isEven(50)); // true
console.log(isEven(75)); // false

Quando o número for negativo esse código irá gerar um RangeError, então podemos corrigir isso dessa forma:

function isEven(n) {
if (n === 0) return true;
if (n === 1) return false;
return n < 0 ? isEven(-n) : isEven(n - 2);
}
console.log(isEven(-1)); // false

O que está acontecendo aqui é que estamos transformando o número negativo em positivo para que a recursão funcione certinho. Ex: -5 vira 5 porque -(-5) é 5.

Até que não foi tão difícil, né? Agora vamos lá contar feijões! 🧐

O exercício chamado Bean Counting consiste em criar uma função que conta quantas vezes um caractere aparece em uma string.

Assim como o exercício de recursão, também temos alguns requisitos:

  • A função deve se chamar countBs.
  • Deve receber uma string como argumento.
  • Deve retornar o número de vezes que o caractere B aparece na string.

Com isso em mente, podemos fazer a seguinte implementação:

function countBs(str) {
let count = 0;
for (let i = 0; i < str.length; i++) {
if (str[i] === "B") {
count++;
}
}
return count;
}
console.log(countBs("BBC")); // 2

A ideia aqui é não usar atalhos como str.split('B').length - 1 e sim percorrer a string caractere por caractere. É muito importante entender como as coisas funcionam por baixo dos panos.

Depois disso o autor pede para escrever outra função chamada countChar que faz a mesma coisa, mas recebe dois argumentos: a string e o caractere que queremos contar.

function countChar(str, char) {
let count = 0;
for (let i = 0; i < str.length; i++) {
if (str[i] === char) {
count++;
}
}
return count;
}
console.log(countChar("kakkerlak", "k")); // 4

Ele pede para reescrever a função countBs para usar a função countChar e assim contar quantas vezes o caractere B aparece na string.

function countBs(str) {
return countChar(str, "B");
}
console.log(countBs("BBC")); // 2

E pronto! Com isso terminamos o capítulo 3 do livro. Agora em diante se prepare para ver coisas mais complexas e interessantes. Isso é uma promessa! 🤞

Pra você que ficou até aqui ⛄

Obrigado por ler até aqui, espero que tenha gostado do conteúdo e que tenha aprendido algo novo.

Se tiver alguma dúvida podemos conversar pelo Discord onde estou quase sempre online, lá mantenho um servidor para a comunidade onde você pode entrar clicando aqui.

Provalmente não teremos mais posts esse ano (não sobre o livro, possivelmente), então aproveito para desejar a você um feliz natal e um próspero ano novo! 🎄

E quase esquecendo, existe um easteregg nesse post, dúvido você encontrar! 😏