Introdução

Achamos que estamos criando o sistema para nossos próprios propósitos. Acreditamos que o estamos fazendo à nossa própria imagem... Mas o computador não é realmente como nós. Ele é uma projeção de uma parte muito pequena de nós mesmos: aquela porção dedicada à lógica, ordem, regra e clareza.

Ellen Ullman, Close to the Machine: Technophilia and Its Discontents
Ilustração de uma chave de fenda ao lado de uma placa de circuito de tamanho semelhante

Este é um livro sobre instruir computadores. Computadores são quase tão comuns quanto chaves de fenda hoje em dia, mas são consideravelmente mais complexos, e fazê-los executar o que você quer nem sempre é fácil.

Se a tarefa que você tem para o seu computador for comum e bem compreendida, como mostrar seu e-mail ou funcionar como uma calculadora, você pode abrir o aplicativo apropriado e começar a trabalhar. Mas, para tarefas únicas ou abertas, muitas vezes não há um aplicativo adequado.

É aí que a programação entra. Programação é o ato de construir um programa—um conjunto de instruções precisas dizendo a um computador o que fazer. Como computadores são criaturas burras e pedantes, programar é fundamentalmente tedioso e frustrante.

Felizmente, se você conseguir superar esse fato—e talvez até apreciar o rigor de pensar em termos que máquinas burras conseguem lidar—programar pode ser recompensador. Isso permite que você faça em segundos coisas que levariam uma eternidade manualmente. É uma forma de fazer sua ferramenta computacional realizar tarefas que antes não conseguia. Além disso, é um excelente jogo de resolução de problemas e pensamento abstrato.

A maior parte da programação é feita com linguagem de programaçãos. Uma linguagem de programação é uma linguagem artificialmente construída usada para instruir computadores. É interessante que a forma mais eficaz que encontramos de nos comunicar com um computador toma tanto emprestado da maneira como nos comunicamos entre nós. Assim como as línguas humanas, linguagens de computador permitem combinar palavras e frases de novas maneiras, tornando possível expressar conceitos sempre novos.

Em certo momento, interfaces baseadas em linguagem, como os prompts do BASIC e do DOS das décadas de 1980 e 1990, eram o principal meio de interação com computadores. Para o uso cotidiano, elas foram em grande parte substituídas por interfaces visuais, que são mais fáceis de aprender, mas oferecem menos liberdade. Ainda assim, se você souber onde procurar, as linguagens continuam lá. Uma delas, JavaScript, está embutida em todo navegador moderno—e, portanto, disponível em praticamente qualquer dispositivo.

Este livro tentará torná-lo familiar o suficiente com essa linguagem para fazer coisas úteis e divertidas com ela.

Sobre programação

Além de explicar JavaScript, vou introduzir os princípios básicos da programação. Programar, ao que parece, é difícil. As regras fundamentais são simples e claras, mas programas construídos sobre essas regras tendem a se tornar complexos o suficiente para introduzir suas próprias regras e complexidades. Você está construindo seu próprio labirinto, de certa forma, e pode facilmente se perder nele.

Haverá momentos em que ler este livro parecerá terrivelmente frustrante. Se você é novo em programação, haverá muito material novo para absorver. Grande parte desse material será então combinada de maneiras que exigem que você faça conexões adicionais.

Cabe a você fazer o esforço necessário. Quando estiver com dificuldade para acompanhar o livro, não tire conclusões precipitadas sobre suas próprias capacidades. Você está bem—apenas precisa continuar. Faça uma pausa, releia partes do material e certifique-se de ler e entender os programas de exemplo e os exercícios. Aprender dá trabalho, mas tudo o que você aprende é seu e tornará o aprendizado futuro mais fácil.

Quando a ação se torna improdutiva, reúna informação; quando a informação se torna improdutiva, durma.

Ursula K. Le Guin, The Left Hand of Darkness

Um programa é muitas coisas. É um pedaço de texto digitado por um programador, é a força diretora que faz o computador fazer o que faz, é dado na memória do computador e, ao mesmo tempo, controla as ações realizadas nessa memória. Analogias que tentam comparar programas a objetos familiares tendem a ser insuficientes. Uma que superficialmente funciona é comparar um programa a uma máquina—muitas partes separadas estão envolvidas, e, para fazer tudo funcionar, precisamos considerar como essas partes se conectam e contribuem para o funcionamento do todo.

Um computador é uma máquina física que atua como hospedeira dessas máquinas imateriais. Computadores em si só conseguem fazer coisas estupidamente simples. A razão de serem tão úteis é que fazem essas coisas com uma velocidade incrivelmente alta. Um programa pode combinar engenhosamente um número enorme dessas ações simples para realizar tarefas muito complicadas.

Um programa é uma construção de pensamento. Não custa nada para construir, não tem peso e cresce facilmente sob nossas mãos ao digitar. Mas, à medida que um programa cresce, cresce também sua complexidade. A habilidade de programar é a habilidade de construir programas que não confundem o programador. Os melhores programas são aqueles que conseguem fazer algo interessante e ainda assim permanecem fáceis de entender.

Alguns programadores acreditam que essa complexidade é melhor administrada usando apenas um pequeno conjunto de técnicas bem compreendidas em seus programas. Eles criaram regras rígidas (“best practices”) que prescrevem a forma que os programas devem ter e permanecem cuidadosamente dentro dessa pequena zona segura.

Isso não é apenas entediante—é ineficaz. Novos problemas frequentemente exigem novas soluções. A área da programação é jovem e ainda está se desenvolvendo rapidamente, além de ser variada o suficiente para comportar abordagens muito diferentes. Há muitos erros terríveis a cometer no design de programas, e você deve ir em frente e cometê-los pelo menos uma vez para entendê-los. A noção de como é um bom programa é desenvolvida com prática, não aprendida a partir de uma lista de regras.

Por que a linguagem importa

No início, no nascimento da computação, não havia linguagens de programação. Os programas eram algo assim:

00110001 00000000 00000000
00110001 00000001 00000001
00110011 00000001 00000010
01010001 00001011 00000010
00100010 00000010 00001000
01000011 00000001 00000000
01000001 00000001 00000001
00010000 00000010 00000000
01100010 00000000 00000000

Este é um programa para somar os números de 1 a 10 e imprimir o resultado: 1 + 2 + ... + 10 = 55. Ele poderia rodar em uma máquina hipotética simples. Para programar os primeiros computadores, era necessário ajustar grandes conjuntos de chaves na posição correta ou perfurar cartões de papelão e alimentá-los no computador. Dá para imaginar como esse procedimento era tedioso e propenso a erros. Mesmo escrever programas simples exigia muita engenhosidade e disciplina. Programas complexos eram quase inconcebíveis.

Claro, inserir manualmente esses padrões arcanos de bits (uns e zeros) dava ao programador uma profunda sensação de ser um poderoso mago. E isso deve valer alguma coisa em termos de satisfação no trabalho.

Cada linha do programa anterior contém uma única instrução. Poderia ser escrito em inglês assim:

  1. Armazene o número 0 na posição de memória 0.

  2. Armazene o número 1 na posição de memória 1.

  3. Armazene o valor da posição de memória 1 na posição de memória 2.

  4. Subtraia o número 11 do valor na posição de memória 2.

  5. Se o valor na posição de memória 2 for 0, continue na instrução 9.

  6. Some o valor da posição de memória 1 à posição de memória 0.

  7. Some o número 1 ao valor da posição de memória 1.

  8. Continue na instrução 3.

  9. Exiba o valor da posição de memória 0.

Embora isso já seja mais legível do que a sopa de bits, ainda é bastante obscuro. Usar nomes em vez de números para as instruções e posições de memória ajuda.

  Set “total” to 0.
  Set “count” to 1.
[loop]
  Set “compare” to “count”.
  Subtract 11 from “compare”.
  If “compare” is 0, continue at [end].
  Add “count” to “total”.
  Add 1 to “count”.
  Continue at [loop].
[end]
  Output “total”.

Você consegue ver como o programa funciona neste ponto? As duas primeiras linhas dão valores iniciais a duas posições de memória: total será usado para acumular o resultado do cálculo, e count acompanhará o número que estamos analisando no momento. As linhas que usam compare provavelmente são as mais confusas. O programa quer verificar se count é igual a 11 para decidir se pode parar. Como nossa máquina hipotética é bastante primitiva, ela só consegue testar se um número é zero e tomar decisões com base nisso. Por isso, usa a posição de memória chamada compare para calcular o valor de count - 11 e toma a decisão com base nesse valor. As duas linhas seguintes somam o valor de count ao resultado e incrementam count em 1 toda vez que o programa decide que count ainda não é 11.

Aqui está o mesmo programa em JavaScript:

let total = 0, count = 1;
while (count <= 10) {
  total += count;
  count += 1;
}
console.log(total);
// → 55

Esta versão nos dá algumas melhorias. Mais importante, não há mais necessidade de especificar como queremos que o programa salte de um ponto a outro—o while cuida disso. Ele continua executando o bloco (delimitado por chaves) abaixo dele enquanto a condição fornecida for verdadeira. Essa condição é count <= 10, que significa “count é menor ou igual a 10”. Não precisamos mais criar um valor temporário e compará-lo com zero, que era apenas um detalhe sem importância. Parte do poder das linguagens de programação é cuidar desses detalhes desinteressantes por nós.

No final do programa, depois que o while termina, a operação console.log é usada para exibir o resultado.

Por fim, aqui está como o programa poderia ser se tivéssemos disponíveis as operações convenientes range e sum, que respectivamente criam uma coleção de números dentro de um intervalo e calculam a soma de uma coleção de números:

console.log(sum(range(1, 10)));
// → 55

A moral da história é que o mesmo programa pode ser expresso de formas longas e curtas, ilegíveis e legíveis. A primeira versão do programa era extremamente obscura, enquanto esta última é quase inglês: log the sum of the range of numbers from 1 to 10 (imprimir a soma do intervalo de números de 1 a 10). (Veremos em capítulos posteriores como definir operações como sum e range.)

Uma boa linguagem de programação ajuda o programador permitindo que ele fale sobre as ações que o computador deve realizar em um nível mais alto. Ela ajuda a omitir detalhes, fornece blocos de construção convenientes (como while e console.log), permite que você defina seus próprios blocos (como sum e range) e torna fácil compor esses blocos.

O que é JavaScript?

JavaScript foi introduzido em 1995 como uma forma de adicionar programas a páginas web no navegador Netscape Navigator. Desde então, a linguagem foi adotada por todos os principais navegadores gráficos. Ela tornou possíveis as aplicações web modernas—ou seja, aplicações com as quais você pode interagir diretamente sem recarregar a página a cada ação. JavaScript também é usado em sites mais tradicionais para fornecer diversas formas de interatividade e funcionalidades inteligentes.

É importante notar que JavaScript quase não tem nada a ver com a linguagem de programação Java. O nome semelhante foi inspirado por motivos de marketing, e não por bom senso. Quando JavaScript foi lançado, a linguagem Java estava sendo fortemente promovida e ganhando popularidade. Alguém achou que seria uma boa ideia aproveitar esse sucesso. Agora ficamos presos ao nome.

Após sua adoção fora da Netscape, um documento de padrão foi escrito para descrever como a linguagem JavaScript deveria funcionar, de modo que os diversos softwares que afirmavam suportá-la realmente fornecessem a mesma linguagem. Isso é chamado de padrão ECMAScript, em referência à organização Ecma International que conduziu a padronização. Na prática, os termos ECMAScript e JavaScript podem ser usados de forma intercambiável—são dois nomes para a mesma linguagem.

Há quem diga coisas terríveis sobre JavaScript. Muitas delas são verdadeiras. Quando fui obrigado a escrever algo em JavaScript pela primeira vez, rapidamente passei a detestá-lo. Ele aceitava quase tudo o que eu digitava, mas interpretava de uma forma completamente diferente do que eu queria dizer. Isso tinha muito a ver com o fato de eu não ter a menor ideia do que estava fazendo, claro, mas há um problema real aqui: JavaScript é ridiculamente permissivo no que aceita. A ideia por trás desse design era facilitar a programação para iniciantes. Na prática, isso torna mais difícil encontrar problemas nos seus programas, porque o sistema não os aponta para você.

Essa flexibilidade também tem suas vantagens. Ela abre espaço para técnicas impossíveis em linguagens mais rígidas e permite um estilo de programação mais agradável e informal. Depois de aprender a linguagem corretamente e trabalhar com ela por um tempo, passei a realmente gostar de JavaScript.

Houve várias versões do JavaScript. ECMAScript versão 3 foi a versão amplamente suportada durante a ascensão da linguagem, aproximadamente entre 2000 e 2010. Durante esse período, trabalhava-se em uma ambiciosa versão 4, que planejava várias melhorias e extensões radicais. Mudar uma linguagem viva e amplamente utilizada de forma tão radical revelou-se politicamente difícil, e o trabalho na versão 4 foi abandonado em 2008. Uma versão 5 bem menos ambiciosa, com apenas algumas melhorias não controversas, foi lançada em 2009. Em 2015, saiu a versão 6, uma grande atualização que incluiu algumas ideias planejadas para a versão 4. Desde então, temos pequenas atualizações anuais.

O fato de JavaScript estar evoluindo significa que os navegadores precisam acompanhar constantemente. Se você estiver usando um navegador antigo, ele pode não suportar todos os recursos. Os projetistas da linguagem são cuidadosos para não fazer mudanças que quebrem programas existentes, então navegadores novos ainda conseguem executar programas antigos. Neste livro, estou usando a versão de 2024 do JavaScript.

Os navegadores web não são as únicas plataformas em que JavaScript é usado. Alguns bancos de dados, como MongoDB e CouchDB, usam JavaScript como linguagem de script e consulta. Diversas plataformas para programação desktop e de servidor, especialmente o projeto Node.js (tema do Capítulo 20), fornecem um ambiente para programar JavaScript fora do navegador.

Código, e o que fazer com ele

Código é o texto que compõe os programas. A maioria dos capítulos deste livro contém bastante código. Acredito que ler código e escrever código são partes indispensáveis do aprendizado de programação. Tente não apenas passar os olhos pelos exemplos—leia-os com atenção e entenda-os. No começo pode ser lento e confuso, mas prometo que você logo pega o jeito. O mesmo vale para os exercícios. Não presuma que entendeu até realmente escrever uma solução funcional.

Recomendo que você teste suas soluções em um interpretador JavaScript de verdade. Assim, você terá feedback imediato sobre se o que está fazendo funciona e, espero, ficará tentado a experimentar e ir além dos exercícios.

Ao ler este livro no seu navegador, você pode editar (e executar) todos os programas de exemplo clicando neles.

Executar os programas definidos neste livro fora do site requer algum cuidado. Muitos exemplos são independentes e devem funcionar em qualquer ambiente JavaScript. Mas o código em capítulos posteriores frequentemente é escrito para um ambiente específico (o navegador ou Node.js) e só pode ser executado ali. Além disso, muitos capítulos definem programas maiores, e os trechos de código neles dependem uns dos outros ou de arquivos externos. O sandbox no site fornece links para arquivos ZIP contendo todos os scripts e dados necessários para executar o código de um determinado capítulo.

Visão geral deste livro

Este livro contém aproximadamente três partes. Os primeiros 12 capítulos discutem a linguagem JavaScript. Os sete capítulos seguintes tratam de navegadores e de como JavaScript é usado para programá-los. Por fim, dois capítulos são dedicados ao Node.js, outro ambiente para programar em JavaScript. Há cinco capítulos de projeto no livro que descrevem programas maiores de exemplo para dar uma ideia de programação real.

A parte da linguagem começa com quatro capítulos que introduzem a estrutura básica do JavaScript. Eles discutem estruturas de controle (como o while que você viu nesta introdução), funções (escrever seus próprios blocos de construção) e estruturas de dados. Depois disso, você será capaz de escrever programas básicos. Em seguida, os Capítulos 5 e 6 introduzem técnicas para usar funções e objetos para escrever código mais abstrato e manter a complexidade sob controle.

Após um primeiro capítulo de projeto, que constrói um robô de entrega simples, a parte da linguagem continua com capítulos sobre tratamento de erros e correção de bugs, expressões regulares (uma ferramenta importante para trabalhar com texto), modularidade (outra defesa contra a complexidade) e programação assíncrona (lidar com eventos que levam tempo). O segundo capítulo de projeto, no qual implementamos uma linguagem de programação, conclui a primeira parte do livro.

A segunda parte do livro, Capítulos 13 até 19, descreve as ferramentas às quais o JavaScript no navegador tem acesso. Você aprenderá a exibir coisas na tela (Capítulos 14 e 17), responder à entrada do usuário (Capítulo 15) e se comunicar pela rede (Capítulo 18). Há novamente dois capítulos de projeto nessa parte: construir um jogo de plataforma e um programa de pintura em pixels.

Capítulo 20 descreve o Node.js, e Capítulo 21 constrói um pequeno site usando essa ferramenta.

Convenções tipográficas

Neste livro, texto escrito em fonte monospaced representa elementos de programas. Às vezes são fragmentos independentes, e às vezes apenas se referem a parte de um programa próximo. Programas (dos quais você já viu alguns) são escritos assim:

function factorial(n) {
  if (n == 0) {
    return 1;
  } else {
    return factorial(n - 1) * n;
  }
}

Às vezes, para mostrar a saída que um programa produz, o resultado esperado é escrito depois dele, com duas barras e uma seta na frente.

console.log(factorial(8));
// → 40320

Boa sorte!