Executando verificação de segurança...
7

🌱╺╸Aprendendo JavaScript do Zero #4

Olá! Estou novamente escrevendo um post, e dessa vez documentarei o inicio do meu aprendizado em JavaScript. Em minha última publicação, analisando os comentários e levando em conta os críterios que utilizei para escolher uma ferramenta de desenvolvimento, decidi aprender JavaScript. Pretendo aprender ele mais ao lado do servidor, ou seja, utilizando o Node.js. Eventualmente aprenderei a manipular o DOM, porém agora este não é o meu foco. De qualquer forma, vamos começar!

Grade inicial

  • Introdução
    Sobre a linguagem e configuração o ambiente.
  • JavaScript básico
    Dados, variáveis, operadores, boolean, funções, objetos, arrays, loops e mais.

Introdução

O JavaScript é uma linguagem interpretada, portanto não precisa do processo de compilação. Ela pode ser utilizada tanto no lado do cliente, quanto no lado do servidor. Deve-se instalar o Node.js para roda o JavaScript fora do navegador, além de escolher um editor de código. O escolhido por mim foi o Visual Studio Code. O meu já está instalado e configurado. Com todas as dependências instaladas, vamos ao que interessa.

JavaScript básico

Para essa parte decidi aprender enquanto faço exercícios. Já tenho uma noção sobre lógica de programação, portanto, enquanto faço desafios, citarei quais fundamentos básicos estou aprendendo seguindo a documentação.

Exercício 1 (Muito Fácil)

Escreva uma função que recebe um número qualquer de
números inteiros como argumentos e retorne a média
aritmética entre eles.

const numeros = [1, 3, 4, 6] // declaro um array que será a entrada da função
let resultadoMedia = 0 // declaro e inicializo a variável que será o resultado de média

function calcMedia(num) { // função que calcula a média
  let soma = 0 // declaro e inicializo a variável que somará os itens do array
  for (let i = 0; i < num.length; i++) { // Laço de repetição declara a variável de índice, e enquanto ela for menor que o total de elementos do array, ela vai se incrementar 1 
    soma += num[i] // retorna pra variável soma a soma de cada item de cada índice do array
  }
  resultadoMedia = soma / num.length // calcula a média
  return resultadoMedia // retorna a média
}

console.log(calcMedia(numeros)) // imprime a média

Nessa questão, observa-se o uso de de dados, variáveis, operadores, funções, arrays e loops. Não tive dificuldades sérias com a lógica, porém ainda sou leigo quando trata-se da sintaxe de JavaScript.

Conclusão

Por agora é só! Fiz esse primeiro exercício, e nesse período de aprendizado da linguagem farei uma postagem por exercício. Obrigado por lerem até aqui e estou ansioso por dicas e críticas. Até a próxima!

Carregando publicação patrocinada...
7

Para quem está começando, eu diria que está bom. Mas tem alguns detalhes que acho bom já ir adiantando. Embora pareça "pesado" para um iniciante, acho interessante pelo menos já pincelar alguns assuntos, pra vc não pegar certos vícios que são difíceis de tirar depois.


Linguagem Compilada vs Linguagem Interpretada

O JavaScript é uma linguagem interpretada, portanto não precisa do processo de compilação.

Na verdade, o buraco é bem mais embaixo. Sei que muita gente faz essa simplificação, mas hoje em dia as coisas estão mais nebulosas e esta separação entre linguagens "compiladas" e "interpretadas" não é mais tão simples assim.

Primeiro (e estou sendo bem pedante): uma linguagem, a grosso modo, nada mais é que uma especificação—um ou mais documentos que descrevem a sua sintaxe, comandos, funcionamento, etc.

É claro que para a linguagem ser útil e podermos escrever programas com ela, precisa ter alguma implementação. Basicamente, um compilador/interpretador para rodar o código. Mas a linguagem em si (a especificação, a sintaxe e forma de funcionamento) não é compilada ou interpretada. As diferentes implementações desta linguagem podem usar um compilador ou interpretador.

O que ocorre é que na prática, a maioria das linguagens acaba tendo uma ou duas implementações mais populares, e estas acabam sendo usadas para definir se a linguagem é interpretada ou compilada. Mas lembre-se que isso é uma característica da implementação, não da linguagem (a menos que alguém diga na especificação que só pode ser um ou outro, mas na prática não fazem isso). Ou seja, é tecnicamente possível ter, por exemplo, interpretador de C (embora não seja nada prático).

E mesmo se considerarmos a implementação, hoje em dia elas estão tão complexas que é difícil cravar se é uma coisa ou outra.

Tá, e o JavaScript é o que então?

Atualmente as implementações mais comuns são o V8 (usada pelo Node.js, Deno, e também pelo Google Chrome e todos os browsers que se baseiam no Chromium) e o SpiderMonkey (usado pelo Firefox). Existem outras, mas são menos usadas.

Muitas destas implementações pegam o código JavaScript e geram um bytecode (um "código binário intermediário"), que depois é executado por uma máquina virtual (virtual machine, ou simplesmente "VM"). E durante a execução (em algumas engines, não sei se em todas) existe ainda um compilador JIT (Just-in-Time Compiler), que pode pegar trechos do bytecode e compilá-los para código de máquina.

Então o V8 e o SpiderMonkey são o que? Eles compilam o código fonte, mas em vez de gerar código de máquina, geram um bytecode. E eles possuem uma VM que executa o bytecode (e muitos dizem que ele "interpreta"). Mas o JIT é outro compilador que atua no bytecode (no código que já foi "compilado"), e gera código de máquina. Então partes são compiladas e outras, pode-se dizer que são interpretadas. Daí a conclusão é que são compiladores ou interpretadores? Ou ambos?

E olha só, é exatamente assim que funciona em Java e C#: o código é compilado, vira um bytecode que é executado por uma VM, que por sua vez possui um JITter, que compila o bytecode e gera código de máquina. Então por que costumam dizer que essas linguagens são compiladas e JavaScript é interpretado? Meu palpite é que essa impressão existe porque no Java cada etapa é feita separadamente (vc "vê" o compilador em ação, afinal), enquanto que no JavaScript é tudo feito de uma vez, muitas vezes debaixo dos panos (como quando ele executa no browser, por exemplo).

Só pra citar outro exemplo, em Python também é feito assim (código -> bytecode -> VM). A única diferença é que na implementação mais comum (o CPython) não tem JIT (embora existam propostas para ter), mas o PyPy (que é outra implementação da linguagem) tem.

Enfim, se for para fazer simplificações, tudo bem. Mas saiba que essa história de "compilado" x "interpretado" é mais complicada do que parece. Leitura adicional:


Sobre o código

Sei que muita gente diz - e até ensina em "cursos" - que tanto faz, mas eu diria para colocar ponto-e-vírgula no final das linhas. Pode parecer "frescura", e sei que o JavaScript "aceita" o código sem ponto-e-vírgula e "funciona", mas isso evita algumas situações bizarras que podem ocorrer se você não usá-los, como essa e essa (veja mais sobre isso aqui).


Não precisa declarar a variável let resultadoMedia fora da função. Não faz sentido, já que ela é o resultado de cada invocação da função. Imagine se vc chamar a função várias vezes, para diferentes arrays. Cada vez que ela executar, a variável será alterada. Mas pra que alterar uma variável externa à função, se este valor só faz sentido lá dentro? Então poderia ser:

function calcMedia(numeros) {
    let soma = 0;
    for (let i = 0; i < numeros.length; i++) {
        soma += numeros[i];
    }
    return soma / numeros.length;
}

Repare que na verdade eu nem usei a variável. Se vc só quer retornar o resultado e não vai usar para mais nada, então nem precisa da variável, pode retornar o resultado do cálculo diretamente.

Se eu quiser jogar o valor da média em uma variável, eu faço isso fora da função:

// atribui o retorno da função a uma variável
// assumindo que o array "notasAluno1" existe, é claro
const mediaAluno1 = calcMedia(notasAluno1);
// ... use mediaAluno1 da forma que precisar

// posso fazer outro cálculo, com outro array, e jogar em outra variável
const mediaAluno2 = calcMedia(notasAluno2);
// ... use mediaAluno2 da forma que precisar

Ou seja, se precisar de uma variável, eu crio. Da forma que vc fez, resultadoMedia seria alterada cada vez que a função fosse chamada, e não tem motivo nenhum pra fazer isso. Mantenha tudo dentro da função, e se precisar guardar o valor em uma variável, faça-o fora da função, pegando o retorno da mesma.

E repare que na função eu mudei o nome do parâmetro para numeros (no plural), assim fica mais claro que pode ter vários números ali. num dá a impressão de que é um só. Sei que ao ler o código, dá pra presumir que é um array, mas ainda acredito que dar nomes melhores ajuda muito na hora de programar. Deixa o código mais claro para quem for ler (não só vc, mas outras pessoas da sua equipe - e até mesmo vc no futuro) e diminui a carga cognitiva (que no médio e longo prazo cansa bastante).


Por fim, como curiosidade, existe também o for..of:

function calcMedia(numeros) {
    let soma = 0;
    for (var n of numeros) {
        soma += n;
    }
    return soma / numeros.length;
}
2

Primeiramente, muito obrigado pelo seu comentário! É bom como um aspirante a programador ter veteranos como você fazendo críticas e dando dicas, de verdade.

Tá, JavaScript é o que então?

Não sei se compreendi totalmente a diferença entre uma linguagem compilada e interpretada, mas concluí que, quando compilada, o processo de compilação é explícito, e quando interpretada, esse processo torna-se menos visível, porém ambas passam por uma compilação. Ainda não lí os artigos que você anexou, então quando ler talvez minha conclusão seja diferente. Aguarde que retornarei sobre quando tiver mais conhecimento.

Sobre o código

Compreendi agora o funcionamento das variáveis! Realmente, não faz sentido guardar na memória um resultado que vem da invocação da função se não for necessário. Em um caso em que eu devesse guardar a notada de cada aluno faria sentido, porém não é necessário no caso de apenas calcular uma média e imprimí-la. O for of realmente é muito mais funcional nessa situação!

Enfim, obrigado por comentar, está sendo de grande ajuda! Conto com o seu apoio, se possível, em minhas próximas postagens!

3

quando compilada, o processo de compilação é explícito, e quando interpretada, esse processo torna-se menos visível

Não. Tanto faz se o processo de compilação é explícito ou implícito. O fato de estar "escondido" não a torna "interpretada".

O que eu quis dizer é que essa separação entre "compilado" e "interpretado" não é tão simples assim. Na prática, não existe mais essa coisa de que uma linguagem só pode ser um dos dois.

Hoje em dia as implementações são softwares complexos e os conceitos acabam se misturando. Engines como o V8 (e os outros já citados) possuem vários componentes, cada um deles complicado por si só (compilador para gerar o bytecode, VM para executá-lo, JIT, etc). E cada um desses componentes pode ser composto por vários outros (apenas um compilador, por exemplo, é um software complexo por si só).

Então na prática o que temos hoje para muitas linguagens é um "híbrido": algumas partes podem ser compiladas, outras podem ser interpretadas, e outras partes que já foram compiladas podem ser novamente - como é o caso do JIT. E cada uma destas etapas pode ter outras intermediárias (exemplo de como ocorre em Java). Então se algumas partes são uma coisa e outras partes são outra coisa, não tem como dizer que é somente uma dessas coisas.

E - novamente - tanto faz se a compilação é explícita ou não. Se tem compilação, não dá pra dizer que é interpretada. Algumas partes podem ser, como é o caso da VM interpretando o bytecode. Mas só por causa disso vai dizer que é tudo interpretado?

Enfim, tire da cabeça essa ideia de que só existem dois grupos excludentes ("compilada" e "interpretada"), e cada linguagem só pode se encaixar em um deles. Pra mim, esta visão está ultrapassada. O que vemos de fato é que muitas implementações fogem completamente deste modelo "só pode ser um". Na verdade, vejo que muitas linguagens - principalmente as mainstream - têm optado pela abordagem "híbrida" com geração de bytecode, que roda em (ou é interpretado por) uma VM, que pode ou não ter um JIT (até PHP tem JIT, a partir da versão 8).