├── .editorconfig ├── .gitignore ├── CONTRIBUTING.md ├── README.md ├── chapters ├── 00-introducao.md ├── 01-valores-tipos-operadores.md ├── 02-estrutura-do-programa.md ├── 03-funcoes.md ├── 04-estruturas-de-dados.md ├── 05-funcoes-de-ordem-superior.md ├── 06-a-vida-secreta-dos-objetos.md ├── 07-pratica-vida-eletronica.md ├── 08-erros-e-manipulacao-de-erros.md ├── 09-expressoes-regulares.md ├── 10-modulos.md ├── 11-pratica-linguagem-de-programacao.md ├── 12-javascript-e-o-navegador.md ├── 13-document-object-model.md ├── 14-manipulando-eventos.md ├── 15-projeto-plataforma-de-jogo.md ├── 16-desenhando-no-canvas.md ├── 17-http.md ├── 18-formularios-e-campos-de-formularios.md ├── 19-projeto-um-programa-de-pintura.md ├── 20-nodejs.md └── 21-projeto-website-de-compartilhamento-de-habilidades.md ├── glossario.md ├── img ├── alert.png ├── bit-sea.png ├── cap4_frac_sqrt.png ├── computer.png ├── confirm.png ├── controlflow_if.png ├── controlflow_loop.png ├── controlflow_nested_if.png ├── controlflow_straight.png ├── cos_sin.svg ├── darkblue.png ├── eloq-js.jpg ├── eloq-js.png ├── exercise_shapes.png ├── game_grid.png ├── html-boxes.jpg ├── html-links.jpg ├── html-tree.jpg ├── linked-list.svg ├── mirror.png ├── mysterious-computer.jpg ├── object.jpg ├── octopus-array.jpg ├── octopus-object.jpg ├── octopus.jpg ├── pizza-squirrel.png ├── pizza-squirrel.svg ├── player_big.png ├── prompt.png ├── re_porcogalinhas.svg ├── skillsharing.png ├── sprites_big.png ├── syntax_tree.png ├── transform.png ├── unicycle.png ├── weresquirrel.png └── weresquirrel.svg ├── pdf └── livro.pdf └── summary.md /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | [*] 3 | charset = utf-8 4 | end_of_line = lf 5 | insert_final_newline = false 6 | trim_trailing_whitespace = true 7 | indent_style = tab 8 | indent_size = 4 9 | 10 | [*.md] 11 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.swp 3 | *.swo 4 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribuições 2 | 3 | ### Por onde começar? 4 | 5 | **1.** Faça o _fork_ do projeto. 6 | 7 | **2.** [Entenda nosso fluxo](#fluxo). 8 | 9 | **3.** [Leia e pratique as boas práticas](#boas-pr%C3%A1ticas). 10 | 11 | ### Fluxo 12 | 13 | É muito fácil contribuir para o projeto. Qualquer tipo de ajuda (seja ela grande ou pequena) é bem-vinda. Se encontrar qualquer parte do livro que possa ser melhorada, essa é uma grande oportunidade para participar ([aqui](https://github.com/braziljs/eloquente-javascript/issues?q=is%3Aopen+is%3Aissue+label%3Amelhorias) é um ótimo lugar para achar coisas que possam ser melhoradas). Caso não saiba por onde começar: 14 | 15 | **1.** Faça referência ao repositório oficial após o _fork_ 16 | 17 | ``` 18 | git remote add upstream git@github.com:braziljs/eloquente-javascript.git 19 | ``` 20 | 21 | **2.** Antes de iniciar o processo de contribuição, crie uma nova branch para fazer suas alterações. 22 | 23 | Alguns exemplos: 24 | 25 | - Para tradução: `git checkout -b traducaoCapX` 26 | - Para revisões: `git checkout -b revisaoCapX` 27 | - Para erros: `git checkout -b correcaoCapX` 28 | 29 | > Use qualquer nome que seja coerente com a contribuição que está sendo feita. 30 | > `X` representa o número do capítulo. 31 | 32 | **3.** Após realizar as alterações, é hora de fazer um commit com uma mensagem coerente do que foi feito. Exemplo: 33 | 34 | ``` 35 | git add --all 36 | git commit -am ‘Adiciona tradução/revisão/melhoria capítulo X linha/linhas Y’ 37 | git push origin traducaoCapX 38 | ``` 39 | 40 | **4.** Envie um _Pull Request_ com as alterações feitas, fazendo referência para o `master` do repositório oficial. 41 | 42 | **5.** Sua contribuição será analisada pela comunidade. Em alguns casos pediremos algumas alterações antes de dar merge. 43 | 44 | Após o merge: 45 | 46 | - Delete a branch utilizada: 47 | 48 | ``` 49 | git checkout master 50 | git push origin :traducaoCapX 51 | git branch -D traducaoCapX 52 | ``` 53 | 54 | - Atualize seu repositório com o repositório oficial: 55 | 56 | ``` 57 | git fetch upstream 58 | git rebase upstream/master 59 | git push -f origin master 60 | ``` 61 | 62 | **6.** Quando iniciar uma nova contribuição, inicie repita o processo pelo passo 2. 63 | 64 | ### Boas práticas 65 | 66 | - **Não traduza termos técnicos e blocos de código** 67 | - Antes de enviar sua contribuição, certifique-se de que está enviando apenas um **único** commit que represente o que foi feito. Caso tenha feito vários commits, [esmague-os](http://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html) antes de fazer o _Pull Request_. 68 | - Caso tenha qualquer tipo de dúvida, abre uma _Issue_ que faremos o possível para te ajudar. 69 | - Não adicione comentários nas issues de “log”. Elas tem apenas a finalidade de armazenar referências ao trabalho de cada capítulo. 70 | - Contribua com as discussões. 71 | - Delimitação para títulos de obras: Utilizar o travessão (—) para o início da frase, nome do autor e logo após o nome da obra, sem alterar nenhum valor. Exemplo: 72 | 73 | > — Master Yuan-Ma, The Book of Programming 74 | 75 | - Estrangeirismo: Utilizar o formato itálico. Exemplo: _bug_ 76 | - Sentido Figurado: Sempre destacar com aspas duplas. 77 | - Citação: Aspas duplas com o sinal de >. Exemplo: 78 | 79 | > “Foo bar” 80 | 81 | - Marcação para código: Utilizar um apóstrofe (\`) para indicar um pedaço de código no meio de um texto (`var foo = undefined`). Ou três apóstrofe com o nome da linguagem de programação na frente (\`\`\`js), para indicar um bloco de código: 82 | 83 | ```js 84 | var foo; 85 | foo = undefined; 86 | ``` 87 | 88 | ### Dúvidas em tradução de termos, palavras, expressões etc… 89 | 90 | Quando estiver em uma situação em que você não sabe exatamente como traduzir uma palavra, termo ou expressão, nós recomendamos que siga os seguintes passos: 91 | 92 | **1.** Abra uma _Issue_ com um título descritivo como por exemplo: “_Como traduzir a palavra/termo “x”?_” e coloque uma descrição fazendo referência à linha e o capítulo que esteja trabalhando. 93 | 94 | **2.** Adicione uma tag `[TODO: ref #][/TODO]` e continue trabalhando no arquivo enquanto não há uma conclusão na _Issue_. Esse processo é importante para facilitar o acesso a itens pendentes e ter uma referência clara onde está ocorrendo a discussão. 95 | 96 | **3.** Após a conclusão da discussão na _Issue_, feche a mesma. Em seguida, remova a tag adicionada no passo 2 e atualize a palavra/termo não traduzido. 97 | 98 | **4.** Como mantemos um arquivo de [glossário](https://github.com/braziljs/eloquente-javascript/blob/master/glossario.md), faça um _Pull Request_ adicionando o novo termo, colocando a referência `#` no termo/palavra em questão para fácil acesso no futuro. 99 | 100 | *** 101 | 102 | Obrigado! :heart: :heart: :heart: 103 | 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JavaScript Eloquente - 2ª edição 2 | 3 | **Uma moderna introdução ao JavaScript, programação e maravilhas digitais.** 4 | 5 | ![JavaScript Eloquente](img/eloq-js.png) 6 | 7 | ## Conteúdo do Livro 8 | 9 | [Introdução](https://github.com/braziljs/eloquente-javascript/blob/master/chapters/00-introducao.md) 10 | 11 | 1. [Valores, Tipos e Operadores](https://github.com/braziljs/eloquente-javascript/blob/master/chapters/01-valores-tipos-operadores.md) - (**Parte 1: Linguagem**) 12 | 1. [Estrutura do Programa](https://github.com/braziljs/eloquente-javascript/blob/master/chapters/02-estrutura-do-programa.md) 13 | 1. [Funções](https://github.com/braziljs/eloquente-javascript/blob/master/chapters/03-funcoes.md) 14 | 1. [Estrutura de Dados: Objeto e Array](https://github.com/braziljs/eloquente-javascript/blob/master/chapters/04-estruturas-de-dados.md) 15 | 1. [Funções de Ordem Superior](https://github.com/braziljs/eloquente-javascript/blob/master/chapters/05-funcoes-de-ordem-superior.md) 16 | 1. [A Vida Secreta dos Objetos](https://github.com/braziljs/eloquente-javascript/blob/master/chapters/06-a-vida-secreta-dos-objetos.md) 17 | 1. [Prática: Vida Eletrônica](https://github.com/braziljs/eloquente-javascript/blob/master/chapters/07-pratica-vida-eletronica.md) 18 | 1. [Erros e Manipulação de Erros](https://github.com/braziljs/eloquente-javascript/blob/master/chapters/08-erros-e-manipulacao-de-erros.md) 19 | 1. [Expressões Regulares](https://github.com/braziljs/eloquente-javascript/blob/master/chapters/09-expressoes-regulares.md) 20 | 1. [Módulos](https://github.com/braziljs/eloquente-javascript/blob/master/chapters/10-modulos.md) 21 | 1. [Prática: A Linguagem de Programação](https://github.com/braziljs/eloquente-javascript/blob/master/chapters/11-pratica-linguagem-de-programacao.md) 22 | 1. [JavaScript e o Navegador](https://github.com/braziljs/eloquente-javascript/blob/master/chapters/12-javascript-e-o-navegador.md) - (**Parte 2: Navegador**) 23 | 1. [O *Document Object Model*](https://github.com/braziljs/eloquente-javascript/blob/master/chapters/13-document-object-model.md) 24 | 1. [Manipulando Eventos](https://github.com/braziljs/eloquente-javascript/blob/master/chapters/14-manipulando-eventos.md) 25 | 1. [Projeto: Plataforma de Jogo](https://github.com/braziljs/eloquente-javascript/blob/master/chapters/15-projeto-plataforma-de-jogo.md) 26 | 1. [Desenhando no Canvas](https://github.com/braziljs/eloquente-javascript/blob/master/chapters/16-desenhando-no-canvas.md) 27 | 1. [HTTP](https://github.com/braziljs/eloquente-javascript/blob/master/chapters/17-http.md) 28 | 1. [Formulários e Campos de Formulários](https://github.com/braziljs/eloquente-javascript/blob/master/chapters/18-formularios-e-campos-de-formularios.md) 29 | 1. [Projeto: Um Programa de Pintura](https://github.com/braziljs/eloquente-javascript/blob/master/chapters/19-projeto-um-programa-de-pintura.md) 30 | 1. [Node.js](https://github.com/braziljs/eloquente-javascript/blob/master/chapters/20-nodejs.md) - (**Parte 3: Node.js**) 31 | 1. [Projeto: Website de Compartilhamento de Habilidades](https://github.com/braziljs/eloquente-javascript/blob/master/chapters/21-projeto-website-de-compartilhamento-de-habilidades.md) 32 | 33 | ## Status Geral do Projeto 34 | 35 | As informações sobre o status e log de cada capítulo estão organizadas [nessa issue](https://github.com/braziljs/eloquente-javascript/issues/254). 36 | 37 | Atualmente, estamos melhorando o que já está traduzido, focando na qualidade e precisão da tradução e entendimento do texto como um todo, além de tentar aplicar a gramática mais correta possível. Vários [contribuidores](https://github.com/braziljs/eloquente-javascript/graphs/contributors) ajudaram em diferentes partes do livro e, por isso, existem diversas oportunidades de melhorias. 38 | 39 | ## Como Contribuir? 40 | 41 | Se você tiver interesse em ajudar, criamos um [guia](https://github.com/braziljs/eloquente-javascript/blob/master/CONTRIBUTING.md) para ajudá-lo e, se tiver qualquer dúvida, basta abrir uma issue. 42 | 43 | ## Informações Importantes 44 | 45 | - Autor: **Marijn Haverbeke** 46 | - [Versão original](http://eloquentjavascript.net) deste livro. 47 | 48 | Licenciado sob a licença [Creative Commons attribution-noncommercial](http://creativecommons.org/licenses/by-nc/3.0/). 49 | 50 | Todo código neste livro também pode ser considerado sob a [licença MIT](http://opensource.org/licenses/MIT). 51 | -------------------------------------------------------------------------------- /chapters/00-introducao.md: -------------------------------------------------------------------------------- 1 | # Introdução 2 | 3 | Esse livro é sobre como fazer com que os computadores façam exatamente o que você quer que eles façam. Hoje em dia, os computadores são tão comuns quanto as chaves de fenda, mas possuem uma complexidade escondida que os torna mais difíceis de se operar e entender. Para muitos, eles continuam sendo não muito familiares e ameaçadores. 4 | 5 | ![Communicating with a computer](../img/computer.png) 6 | 7 | Nós encontramos duas maneiras efetivas para aproximar o espaço vazio que existe na comunicação entre nós, organismos biológicos com um talento para o raciocínio espacial e social, e os computadores, que não possuem sentimentos e são apenas manipuladores de dados. A primeira delas, é baseada em usar nosso senso do mundo físico e construir interfaces que simulam esse mundo, permitindo manipular estruturas na tela com os nossos dedos. Isso funciona muito bem para interações casuais com a máquina. 8 | 9 | Entretanto, ainda não encontramos uma maneira boa de usar a abordagem de apontar e clicar para comunicar ao computador as coisas que o designer da interface não previu. Para interfaces mais gerais, como instruir o computador a executar tarefas arbitrárias, tivemos mais sorte com uma abordagem que utiliza nosso talento para linguagem: ensinar uma linguagem à maquina. 10 | 11 | As linguagens humanas possibilitam que palavras e frases sejam combinadas de diferentes maneiras, nos permitindo falar diferentes coisas. As linguagens de computador, normalmente menos flexíveis em sua gramática, seguem um princípio similar. 12 | 13 | O uso da computação casual se tornou cada vez mais popular nos últimos vinte anos e as interfaces baseadas em linguagens, que era a forma na qual as pessoas interagiam com os computares, foram amplamente substituídas por interfaces gráficas. Mesmo assim, elas continuam por aí, basta saber onde procurá-las. Uma linguagem específica chamada JavaScript está presente em praticamente todos os navegadores e, por isso, está disponível em quase todos os aparelhos. 14 | 15 | Esse livro tem o objetivo de familiarizá-lo o suficiente com essa linguagem para que você seja capaz de fazer com que o computador faça o que você quiser. 16 | 17 | ## Sobre Programação 18 | 19 | > Eu não esclareço aqueles que não têm vontade de aprender, nem desperto aqueles que não estão ansiosos para dar uma explicação a si mesmos. Se eu mostrei um lado de um quadrado e eles não conseguem chegar nos outros três, eu não deveria passar pelos mesmos pontos novamente. 20 | > 21 | > — Confúcio 22 | 23 | Antes de explicar o JavaScript, irei introduzir também os princípios básicos de programação. Programação é de fato difícil. As regras fundamentais são geralmente simples e claras. Entretanto, programas construídos em cima dessas regras tendem a se tornar complexos, introduzindo suas próprias regras e complexidades adicionais. De certa forma, você estará construindo o seu próprio labirinto e, talvez, possa acabar se perdendo nele. 24 | 25 | Haverá momentos de frustração quando estiver lendo esse livro e, se você é novo em programação, haverá uma grande quantidade de material para ser digerido. Durante a leitura, muitos desses conceitos serão _combinados_ de várias formas, forçando-o a fazer novas conexões. 26 | 27 | Fica a seu critério saber qual o nível de esforço necessário. Quando estiver passando por dificuldades para acompanhar o livro, não tire conclusões imediatas sobre sua própria capacidade. Você estará bem, apenas não desista. Tire um tempo de descanso, releia algum material anterior e _sempre_ certifique-se de que leu e entendeu os programas apresentados nos exemplos e nos exercícios. Aprender é um trabalho árduo, mas tudo o que for aprendido será completamente seu e ajudará com que o aprendizado posterior seja ainda mais fácil. 28 | 29 | > O programador é um criador de universos nos quais ele é o único responsável. Universos com complexidades totalmente ilimitadas podem ser criados na forma de programas de computador. 30 | > 31 | > — Joseph Weizenbaum, Computer Power and Human Reason 32 | 33 | Um programa pode ser considerado muitas coisas. Ele é um pedaço de texto digitado por um programador, a força que direciona o computador a fazer o que ele faz e, também, os dados contidos na memória do computador, controlando as ações executadas nessa mesma memória. Analogias que tentam comparar programas aos objetos que conhecemos, normalmente tendem a ser insuficientes. Uma dessas comparações superficiais é com uma máquina, com várias partes separadas que normalmente estão relacionadas e, para fazer com que a máquina toda funcione, precisamos considerar a maneira nas quais essas partes estão conectadas e como cada uma contribui para a operação da máquina como um todo. 34 | 35 | Um computador é uma máquina construída para atuar como um hospedeiro para essas máquinas imateriais. Os computadores por si sós, conseguem apenas fazer coisas fáceis e pouco complicadas. A razão deles serem tão úteis, é que eles conseguem executar essas coisas em uma velocidade incrivelmente rápida. Um programa pode combinar uma grande quantidade dessas coisas simples a fim de executar coisas mais complicadas. 36 | 37 | Para alguns de nós, escrever programas de computador é um fascinante jogo. Um programa é uma construção do pensamento. Não possui custos de construção, é leve e cresce facilmente com a digitação feita por nossas mãos. 38 | 39 | Entretanto, se não formos cuidadosos, o tamanho e a complexidade de um programa pode crescer e ficar fora de controle, confundindo, até mesmo, a pessoa que o criou. Manter os programas sob controle é o maior desafio da programação. Quando um programa funciona, é lindo. A arte de programar é, basicamente, a habilidade de controlar a complexidade. Um ótimo programa é suave e simples em sua própria complexidade. 40 | 41 | Muitos programadores acreditam que essa complexidade é melhor gerenciada usando, em seus programas, apenas um pequeno conjunto de técnicas bem entendidas. Eles criaram uma série de regras rígidas ("boas práticas") recomendando a forma que os programas deveriam ter. Os mais zelosos entre eles, vão considerar como _maus programadores_ aqueles que saem dessa pequena zona de segurança. 42 | 43 | Quanta hostilidade em relação à riqueza da programação, tentar reduzi-la a algo simples e previsível, colocando um tabu em todos os estranhos e bonitos programas. A dimensão das técnicas de programação é enorme e fascinante em sua diversidade e, ainda assim, amplamente inexplorada. É certamente muito perigoso atrair programadores inexperientes nesses tipos de confusões, entretanto, você deve seguir com cautela e manter o seu senso comum em relação a elas. Conforme você aprende, sempre haverá novos territórios e desafios a serem explorados. Programadores que se recusam a continuar explorando irão estagnar, esquecer da alegria que é programar e acabarão ficando entediados com as coisas que constroem. 44 | 45 | ## Porque linguagens importam? 46 | 47 | No início, quando a computação nasceu, não haviam linguagens de programação. Os programas eram parecidos com algo assim: 48 | 49 | ``` 50 | 00110001 00000000 00000000 51 | 00110001 00000001 00000001 52 | 00110011 00000001 00000010 53 | 01010001 00001011 00000010 54 | 00100010 00000010 00001000 55 | 01000011 00000001 00000000 56 | 01000001 00000001 00000001 57 | 00010000 00000010 00000000 58 | 01100010 00000000 00000000 59 | ``` 60 | 61 | Esse é um programa que soma os números de 1 a 10 e imprime o resultado: `1 + 2 + … + 10 = 55`. Ele poderia ser executado em qualquer máquina simples. Para programar os computadores antigos, era necessário configurar longos conjuntos de chaves na posição correta ou, então, fazer perfurações em cartões que eram usados para alimentar o computador. Você provavelmente deve estar imaginando como tedioso e propenso a erros esse procedimento era. Até para escrever programas simples precisava de muita habilidade e disciplina. Os programas mais complexos eram praticamente inimagináveis de serem criados. 62 | 63 | É claro que inserir esses padrões "arcanos" de bits (zeros e uns) dava ao programador a profunda sensação de ser um poderoso mago, e isso devia significar alguma coisa em relação ao sentimento de satisfação em seu trabalho. 64 | 65 | Cada linha do programa anterior contém uma única instrução e poderia ser escrito assim: 66 | 67 | ``` 68 | 1. Armazene o número 0 na posição de memória 0. 69 | 2. Armazene o número 1 na posição de memória 1. 70 | 3. Armazene o valor contido na posição de memória 1 na posição de memória 2. 71 | 4. Subtraia o número 11 do valor contido na posição de memória 2. 72 | 5. Se o valor contido na posição de memória 2 for o número zero, continue com a instrução número 9. 73 | 6. Adicione o valor contido na posição de memória 1 na posição de memória 0. 74 | 7. Adicione o número 1 ao valor contido na posição de memória 1. 75 | 8. Continue com a instrução número 3. 76 | 9. Imprima o valor contido na posição de memória 0. 77 | ``` 78 | 79 | Embora isso seja mais legível do que aquela sopa de bits, ainda assim continua bastante desagradável. Ajudaria um pouco usar nomes ao invés de números para as instruções e posições de memória. 80 | 81 | ``` 82 | Coloque 0 em "total". 83 | Coloque 1 em "count". 84 | [loop] 85 | Coloque "compare” em "count". 86 | Subtraia 11 de "compare". 87 | Se "compare” for zero, continue no [fim]. 88 | Adicione "count” em "total". 89 | Adicione 1 em "count". 90 | Continue no [loop]. 91 | [fim] 92 | Imprima "total". 93 | ``` 94 | 95 | Você consegue perceber como esse programa funciona? As duas primeiras linhas informam os valores iniciais de duas posições na memória: `total` será usado para construir o resultado do cálculo e `count` manterá a referência ao número que nós atualmente estamos olhando. As linhas que utilizam `compare` são provavelmente as mais estranhas. O programa deseja verificar se `count` é igual a 11 para decidir se precisa parar a sua execução. Devido ao fato de que nossa máquina hipotética é bastante primitiva, ela pode apenas testar se um número é zero e tomar uma decisão baseada nesse fato. Por isso, ela usa o espaço de memória chamado `compare` para calcular o valor de `count - 11` e tomar a decisão baseada no valor desse resultado. As próximas duas linhas adicionam o valor de `count` ao resultado e incrementa uma unidade em `count` toda vez que o programa decide que `count` ainda não é o valor 11. 96 | 97 | Aqui temos o mesmo programa em JavaScript: 98 | 99 | ```js 100 | var total = 0, count = 1; 101 | while (count <= 10) { 102 | total += count; 103 | count += 1; 104 | } 105 | console.log(total); 106 | // → 55 107 | ``` 108 | 109 | Essa versão nos dá algumas melhorias. A mais importante delas é o fato de que não é mais necessário especificar a forma que desejamos que o programa salte para o início ou fim. A construção `while` é responsável por cuidar disso, continuando a execução do bloco (envolvido pelas chaves) abaixo dela enquanto a condição de execução que foi informada continua válida. Essa condição é dada por `count <= 10`, que significa "`count` é menor ou igual a 10". Nós não precisamos criar um valor temporário e compará-lo a zero, que era um detalhe não muito interessante. Parte do poder das linguagens de programação é o fato de que elas tomam conta desses detalhes não muito interessantes para nós. 110 | 111 | No final do programa, logo depois que a construção `while` finalizou a sua execução, a operação `console.log` é aplicada ao resultado final para que ele seja o nosso dado de saída. 112 | 113 | Por fim, aqui está um exemplo de como o programa seria se tivéssemos disponíveis as operações `range` (intervalo) e `sum` (soma), que criariam uma coleção de números em um intervalo definido e calcularia a soma de uma coleção de números respectivamente: 114 | 115 | ```js 116 | console.log(sum(range(1, 10))); 117 | // → 55 118 | ``` 119 | 120 | A moral de toda essa história é que o mesmo programa pode ser expresso de formas curtas e longas, legíveis ou não. A primeira versão do programa era extremamente complicada e obscura, enquanto que a última versão é praticamente legível usando a linguagem natural: `log` (imprima) a `sum` (soma) de um `range` (intervalo) de números de 1 a 10. Iremos aprender em [capítulos posteriores](./04-estruturas-de-dados.md) como construir operações como `sum` e `range`. 121 | 122 | Uma boa linguagem de programação ajuda o programador permitindo-o conversar em alto nível com o computador sobre as ações que ele deve realizar. Ela também ajuda a omitir detalhes não muito interessantes, fornece blocos convenientes usados na construção dos programas (tais como `while` e `console.log`) e permite que você defina seus próprios blocos de construção (tais como `sum` e `range`), fazendo com que esses blocos sejam facilmente agrupados. 123 | 124 | ## O que é JavaScript? 125 | 126 | O JavaScript foi introduzido em 1995 como uma forma de adicionar programas às páginas web do navegador Netscape. A linguagem, desde então, foi adotada por todos os outros grandes navegadores web que possuem interfaces gráficas. Ele tornou as aplicações modernas possíveis, fazendo com que você não tenha que recarregar a página inteira quando for necessário realizar interações diretas com a aplicação. Além disso, ele é usado em páginas web mais tradicionais, fornecendo diferentes maneiras de criar interatividade e inteligência. 127 | 128 | É importante observar que o JavaScript não tem praticamente nada a ver com a linguagem de programação Java. O nome parecido foi inspirado por considerações de marketing ao invés do bom senso. Quando o JavaScript foi introduzido, a linguagem Java estava sendo fortemente divulgada e ganhando bastante popularidade. Assim, alguém pensou que poderia ser uma boa ideia tentar aproveitar um pouco desse sucesso. Hoje, estamos presos a esse nome. 129 | 130 | Depois que o JavaScript foi adotado fora do Netscape, um documento padrão foi escrito para descrever a maneira na qual a linguagem deveria funcionar, garantindo que as diferentes partes dos softwares que afirmavam suportar JavaScript estavam, de fato, falando sobre a mesma linguagem. Esse documento é chamado de padrão ECMAScript, nomeado pela organização internacional Ecma, que foi responsável pela padronização. Na prática, os termos ECMAScript e JavaScript podem ser usados como sinônimos, pois são dois nomes para a mesma linguagem. 131 | 132 | Existem aqueles que irão falar coisas _terríveis_ sobre a linguagem JavaScript. Muitas dessas coisas são verdades. Quando fui obrigado a escrever algo em JavaScript pela primeira vez, rapidamente comecei a odiá-lo, pois a linguagem aceitava praticamente tudo que eu digitava e interpretava de uma forma que era completamente diferente de como eu queria. É evidente que isso estava muito relacionado ao fato de que eu não tinha a mínima ideia do que eu estava fazendo. Porém, existe um grande problema nisso: O JavaScript é ridiculamente liberal em relação ao que ele permite. A ideia por trás desse design era a de que isso deveria fazer com que o JavaScript fosse fácil para iniciantes. Na realidade, isso acaba fazendo com que seja bastante difícil encontrar problemas nos seus programas, pois o sistema não aponta onde eles estão. 133 | 134 | Mesmo assim, essa flexibilidade também tem suas vantagens. Ela dá espaço para muitas técnicas que são impossíveis de serem realizadas em linguagens mais rígidas e, como você verá em breve (por exemplo no [Capítulo 10](./10-modulos.md)), ela pode ser usada para superar algumas das limitações do JavaScript. Após aprender corretamente e trabalhar por um tempo com a linguagem, aprendi a realmente _gostar_ do JavaScript. 135 | 136 | Existem diversas versões do JavaScript. A versão 3 do ECMAScript era a versão que tinha amplamente mais suporte na época em que o JavaScript estava em ascensão para se tornar dominante, aproximadamente entre os anos 2000 e 2010. Durante esse período, a ambiciosa versão 4 estava sendo desenvolvida, incluindo planos de melhorias radicais e extensões para a linguagem. Porém, mudar de forma radical uma linguagem viva e amplamente usada acabou provando ser politicamente muito difícil e, por isso, a versão 4 foi abandonada em 2008, fazendo com que a versão 5, bem menos ambiciosa, fosse lançada em 2009. Nós estamos, atualmente, em um ponto em que todos os grandes navegadores suportam a versão 5, que será a versão que iremos usar nesse livro. A versão 6 ainda está no processo para ser finalizada, e alguns navegadores já estão suportando algumas de suas novas funcionalidades. 137 | 138 | Navegadores web não são as únicas plataformas nas quais o JavaScript é usado. Alguns bancos de dados, como MongoDB e CouchDB, usam o JavaScript como sua linguagem de script e consulta. Muitas plataformas para desktop, tanto quanto as de programação no servidor, sendo o mais notável o projeto Node.js (que é o assunto do [Capítulo 20](./20-nodejs.md)), estão fornecendo um poderoso ambiente para programar JavaScript fora do navegador. 139 | 140 | ## Código, e o que fazer com ele 141 | 142 | Código é o texto que compõe os programas. Muitos capítulos desse livro contêm uma boa quantidade de código. Na minha experiência, ler e escrever código são partes indispensáveis do aprendizado da programação, então, tente não apenas olhar rapidamente os exemplos. Leia-os com atenção e entenda-os. Isso pode ser mais lento e confuso no início, mas prometo que você irá rapidamente pegar o jeito. O mesmo é verdade para os exercícios. Não assuma que você os entendeu até você escrever, de fato, uma solução que funcione. 143 | 144 | Eu recomendo que você teste suas soluções dos exercícios em um interpretador JavaScript real. Dessa forma, você receberá _feedback_ imediato sobre o funcionamento, ou não, do que você fez. Além disso, espero que você fique tentado a experimentar coisas novas e ir além dos exercícios. 145 | 146 | Quando estiver lendo esse livro no seu navegador, você pode editar e executar todos os programas dos exemplos clicando neles. 147 | 148 | Se quiser executar os programas desse livro em um ambiente externo ao ambiente do livro, alguns cuidados devem ser tomados. Muitos exemplos são independentes e funcionam em qualquer ambiente que suporte JavaScript. Entretanto, o código usado nos últimos capítulos são escritos para executar em um ambiente específico (em alguns casos no navegador e em outros Node.js), sendo apenas possível executá-los neles. Além disso, muitos capítulos definem programas grandes, sendo que algumas partes dos códigos que aparecem nesses programas dependem umas das outras ou, então, de arquivos externos. O ambiente de execução do site fornece links para arquivos _Zip_ que contêm todos os scripts e dados necessários para executar o código de um dado capítulo. 149 | 150 | ## Visão geral desse livro 151 | 152 | Esse livro contém três partes. Os primeiros onze capítulos falam sobre a linguagem JavaScript em si. Em seguida, os próximos oito capítulos são relacionados aos navegadores web e como o JavaScript é usado para programar neles. Por fim, os últimos dois capítulos são dedicados ao Node.js, que é outro ambiente no qual é possível programar usando JavaScript. 153 | 154 | No decorrer do livro, haverá cinco _projetos_ que descrevem exemplos de programas maiores, dando o gosto da programação real de fato. Iremos trabalhar, em ordem, construindo uma [simulação de vida artificial](./07-pratica-vida-eletronica.md), uma [linguagem de programação](./11-pratica-linguagem-de-programacao.md), uma [plataforma de jogo](./15-projeto-plataforma-de-jogo.md), um [programa de pintura](./19-projeto-um-programa-de-pintura.md) e, por último, um [website dinâmico](./21-projeto-website-de-compartilhamento-de-habilidades.md). 155 | 156 | A parte correspondente à linguagem começa com quatro capítulos que introduzem as estruturas básicas do JavaScript. Serão introduzidas estruturas de controle (tais como a palavra `while` que foi mostrada nessa introdução), funções (escrever suas próprias operações) e estrutura de dados. Após isso, você será capaz de escrever programas simples. Em seguida, os capítulos [5](./05-funcoes-de-ordem-superior.md) e [6](./06-a-vida-secreta-dos-objetos.md) irão introduzir técnicas para usar funções e objetos a fim de escrever código mais abstrato e manter a complexidade sob controle. 157 | 158 | Após o [primeiro projeto](./07-pratica-vida-eletronica.md), a primeira parte do livro continua com os capítulos sobre [manipulação e conserto de erros](./08-erros-e-manipulacao-de-erros.md), [expressões regulares](./09-expressoes-regulares.md) (uma ferramenta importante para trabalhar com dados de texto) e [modularidade](./10-modulos.md), que é uma outra arma contra a complexidade. O [segundo projeto](./11-pratica-linguagem-de-programacao.md) conclui a primeira parte do livro. 159 | 160 | ## Convenções Tipográficas 161 | 162 | Nesse livro, os textos escritos em fonte `mono-espaçada` representarão elementos de programas. Algumas vezes serão fragmentos autossuficientes e em outras, apenas referências para alguma parte de um programa próximo. Programas (os quais você já viu alguns) são escritos assim: 163 | 164 | ```js 165 | function fac(n) { 166 | if (n == 0) 167 | return 1; 168 | else 169 | return fac(n - 1) * n; 170 | } 171 | ``` 172 | 173 | Algumas vezes, para mostrar a saída que um programa produz, o resultado esperado será escrito após o mesmo, com duas barras e uma seta na frente. 174 | 175 | ```js 176 | console.log(fac(8)); 177 | // → 40320 178 | ``` 179 | 180 | Boa Sorte! 181 | -------------------------------------------------------------------------------- /chapters/01-valores-tipos-operadores.md: -------------------------------------------------------------------------------- 1 | # Valores, Tipos e Operadores 2 | 3 | > Abaixo da parte superficial da máquina, o programa se movimenta. Sem esforço, ele se expande e se contrai. Com grande harmonia, os elétrons se espalham e se reagrupam. As formas no monitor são como ondulações na água. A essência permanece invisível por baixo. 4 | > 5 | > — Master Yuan-Ma, The Book of Programming 6 | 7 | Dentro do mundo do computador, há somente dados. Você pode ler, modificar e criar novos dados, entretanto, qualquer coisa que não seja um dado simplesmente não existe. Todos os dados são armazenados em longas sequências de bits e são, fundamentalmente, parecidos. 8 | 9 | Bits podem ser qualquer tipo de coisa representada por dois valores, normalmente descritos como zeros e uns. Dentro do computador, eles representam formas tais como uma carga elétrica alta ou baixa, um sinal forte ou fraco ou até um ponto na superfície de um CD que possui brilho ou não. Qualquer pedaço de informação pode ser reduzido a uma sequência de zeros e uns e, então, representados por bits. 10 | 11 | Como um exemplo, pense sobre a maneira que o número 13 pode ser armazenado em bits. A forma usual de se fazer esta analogia é a forma de escrevermos números decimais, mas ao invés de 10 dígitos, temos apenas 2. E, ao invés de o valor de um dígito aumentar dez vezes sobre o dígito após ele, o valor aumenta por um fator de 2. Estes são os bits que compõem o número treze, com o valor dos dígitos mostrados abaixo deles: 12 | 13 | ``` 14 | 0 0 0 0 1 1 0 1 15 | 128 64 32 16 8 4 2 1 16 | ``` 17 | 18 | Assim, este é o número binário 00001101, ou 8 + 4 + 1, que equivale a 13. 19 | 20 | ## Valores 21 | 22 | Imagine um mar de bits, um oceano deles. Um computador moderno possui mais de trinta bilhões de bits em seu armazenamento volátil de dados. Já em armazenamento de dados não voláteis, sendo eles o disco rígido ou algo equivalente, tende a ter uma ordem de magnitude ainda maior. 23 | 24 | ![Bit Sea](../img/bit-sea.png) 25 | 26 | Para que seja possível trabalhar com tais quantidades de bits sem ficar perdido, você pode separá-los em partes que representam pedaços de informação. No ambiente JavaScript, essas partes são chamadas de _valores_. Embora todos os valores sejam compostos por bits, cada valor exerce um papel diferente e todo valor possui um tipo que determina o seu papel. Existem seis tipos básicos de valores no JavaScript: números, _Strings_, _Booleanos_, objetos, funções e valores indefinidos. 27 | 28 | Para criar um valor, você deve simplesmente invocar o seu nome. Isso é bastante conveniente, pois você não precisa de nenhum material extra para construí-los e muito menos ter que pagar algo por eles. Você só chama por ele e pronto, você o tem. É claro que eles não são criados do nada. Todo valor precisa estar armazenado em algum lugar e, se você quiser usar uma quantidade enorme deles ao mesmo tempo, você pode acabar ficando sem bits. Felizmente, esse é um problema apenas se você precisa deles simultaneamente. A medida que você não utiliza um valor, ele será dissipado, fazendo com que seus bits sejam reciclados, disponibilizando-os para serem usados na construção de outros novos valores. 29 | 30 | Esse capítulo introduz os elementos que representam os átomos dos programas JavaScript, que são os simples tipos de valores e os operadores que podem atuar sobre eles. 31 | 32 | ## Números 33 | 34 | Valores do tipo _número_ são, sem muitas surpresas, valores numéricos. Em um programa JavaScript, eles são escritos assim: 35 | 36 | ```js 37 | 13 38 | ``` 39 | 40 | Coloque isso em um programa e isso fará com que padrões de bits referentes ao número 13 sejam criados e passe a existir dentro da memória do computador. 41 | 42 | O JavaScript utiliza um número fixo de bits, mais precisamente 64 deles, para armazenar um único valor numérico. Existem apenas algumas maneiras possíveis que você pode combinar esses 64 bits, ou seja, a quantidade de números diferentes que podem ser representados é limitada. Para um valor _N_ de dígitos decimais, a quantidade de números que pode ser representada é _10ⁿ_. De forma similar, dado 64 dígitos binários, você pode representar 2⁶⁴ número diferentes, que é aproximadamente 18 quintilhões (o número 18 com 18 zeros após ele). Isso é muito. 43 | 44 | A memória do computador costumava ser bem menor e, por isso, as pessoas usavam grupos de 8 ou 16 bits para representar os números. Por isso, era muito fácil extrapolar essa capacidade de armazenamento tão pequena usando números que não cabiam nesse espaço. Hoje em dia, até os computadores pessoais possuem memória suficiente, possibilitando usar grupos de 64 bits, sendo apenas necessário se preocupar em exceder o espaço quando estiver lidando com números extremamente grandes. 45 | 46 | Entretanto, nem todos os números inteiros menores do que 18 quintilhões cabem em um número no JavaScript. Os bits também armazenam números negativos, sendo que um desses bits indica o sinal do número. Um grande problema é que números fracionários também precisam ser representados. Para fazer isso, alguns bits são usados para armazenar a posição do ponto decimal. Na realidade, o maior número inteiro que pode ser armazenado está na região de 9 quatrilhões (15 zeros), que ainda assim é extremamente grande. 47 | 48 | Números fracionários são escritos usando um ponto. 49 | 50 | ```js 51 | 9.81 52 | ``` 53 | 54 | Para números muito grandes ou pequenos, você pode usar a notação científica adicionando um “e” (de “expoente”) seguido do valor do expoente: 55 | 56 | ```js 57 | 2.998e8 58 | ``` 59 | 60 | Isso é 2.998 x 10⁸ = 299800000. 61 | 62 | Cálculos usando números inteiros menores que os 9 quadrilhões mencionados, serão com certeza precisos. Infelizmente, cálculos com número fracionários normalmente não são precisos. Da mesma forma que π (pi) não pode ser expresso de forma precisa por uma quantidade finita de dígitos decimais, muitos números perdem sua precisão quando existem apenas 64 bits disponíveis para armazená-los. Isso é vergonhoso, porém causa problemas apenas em algumas situações específicas. O mais importante é estar ciente dessa limitação e tratar números fracionários como aproximações e não como valores precisos. 63 | 64 | ## Aritmética 65 | 66 | A principal coisa para se fazer com números são cálculos aritméticos. As operações como adição ou multiplicação recebem dois valores numéricos e produzem um novo número a partir deles. Elas são representadas dessa forma no JavaScript: 67 | 68 | ```js 69 | 100 + 4 * 11 70 | ``` 71 | 72 | Os símbolos `+` e `*` são chamados de _operadores_. O primeiro é referente à adição e o segundo à multiplicação. Colocar um operador entre dois valores irá aplicá-lo a esses valores e produzirá um novo valor. 73 | 74 | O significado do exemplo anterior é “adicione 4 e 100 e, em seguida, multiplique esse resultado por 11” ou a multiplicação é realizada antes da adição? Como você deve ter pensado, a multiplicação acontece primeiro. Entretanto, como na matemática, você pode mudar esse comportamento envolvendo a adição com parênteses. 75 | 76 | ```javascript 77 | (100 + 4) * 11 78 | ``` 79 | 80 | Para subtração existe o operador `-` e para a divisão usamos o operador `/`. 81 | 82 | Quando os operadores aparecem juntos sem parênteses, a ordem que eles serão aplicados é determinada pela _precedência_ deles. O exemplo mostra que a multiplicação ocorre antes da adição. O operador `/` possui a mesma precedência que `*` e, de forma similar, os operadores `+` e `-` possuem a mesma precedência entre si. Quando vários operadores de mesma precedência aparecem próximos uns aos outros, como por exemplo `1 - 2 + 1`, eles são aplicados da esquerda para a direita: `(1 - 2) + 1`. 83 | 84 | Essas regras de precedência não são coisas com as quais você deve se preocupar. Quando estiver em dúvida, apenas adicione os parênteses. 85 | 86 | Existe mais um operador aritmético que você talvez não reconheça imediatamente. O símbolo `%` é usado para representar a operação de _resto_. `X % Y` é o resto da divisão de `X` por `Y`. Por exemplo, `314 % 100` produz `14` e `144 % 12` produz `0`. A precedência do operador resto é a mesma da multiplicação e divisão. Você ouvirá com frequência esse operador ser chamado de _modulo_ mas, tecnicamente falando, _resto_ é o termo mais preciso. 87 | 88 | ## Números Especiais 89 | 90 | Existem três valores especiais no JavaScript que são considerados números, mas não se comportam como números normais. 91 | 92 | Os dois primeiros são `Infinity` e `-Infinity`, que são usados para representar os infinitos positivo e negativo. O cálculo `Infinity - 1` continua sendo `Infinity`, assim como qualquer outra variação dessa conta. Entretanto, não confie muito em cálculos baseados no valor infinito, pois esse valor não é matematicamente sólido e rapidamente nos levará ao próximo número especial: `NaN`. 93 | 94 | `NaN` é a abreviação de “_not a number_” (não é um número), mesmo sabendo que ele é um valor do tipo número. Você receberá esse valor como resultado quando, por exemplo, tentar calcular `0 / 0` (zero dividido por zero), `Infinity - Infinity` ou, então, realizar quaisquer outras operações numéricas que não resultem em um número preciso e significativo. 95 | 96 | ## _Strings_ 97 | 98 | O próximo tipo básico de dado é a _String_. _Strings_ são usadas para representar texto, e são escritas delimitando o seu conteúdo entre aspas. 99 | 100 | ```js 101 | "Patch my boat with chewing gum" 102 | 'Monkeys wave goodbye' 103 | ``` 104 | 105 | Ambas as aspas simples e duplas podem ser usadas para representar _Strings_, contanto que as aspas abertas sejam iguais no início e no fim. 106 | 107 | Quase tudo pode ser colocado entre aspas e o JavaScript criará um valor do tipo _String_ com o que quer que seja. Entretanto, alguns caracteres são mais difíceis. Você pode imaginar como deve ser complicado colocar aspas dentro de aspas. Além disso, os caracteres _newlines_ (quebra de linhas, usados quando você aperta _Enter_), também não podem ser colocados entre aspas. As _Strings_ devem permanecer em uma única linha. 108 | 109 | Para que seja possível incluir tais caracteres em uma _String_, a seguinte notação é utilizada: toda vez que um caractere de barra invertida (`\`) for encontrado dentro de um texto entre aspas, ele indicará que o caractere seguinte possui um significado especial. Isso é chamado de _escapar_ o caractere. Uma aspa que se encontra logo após uma barra invertida não representará o fim da _String_ e, ao invés disso, será considerada como parte do texto dela. Quando um caractere `n` aparecer após uma barra invertida, ele será interpretado como uma quebra de linha e, de forma similar, um `t` significará um caractere de tabulação. Considere a seguinte _String_: 110 | 111 | ```js 112 | "This is the first line\nAnd this is the second" 113 | ``` 114 | 115 | O texto na verdade será: 116 | 117 | ``` 118 | This is the first line 119 | And this is the second 120 | ``` 121 | 122 | Existe, obviamente, situações nas quais você vai querer que a barra invertida em uma _String_ seja apenas uma barra invertida e não um código especial. Nesse caso, se duas barras invertidas estiverem seguidas uma da outra, elas se anulam e apenas uma será deixada no valor da _String_ resultante. Essa é a forma na qual a _String_ “`A newline character is written like “\n”.`” pode ser representada: 123 | 124 | ```js 125 | "A newline character is written like \"\\n\"." 126 | ``` 127 | 128 | _Strings_ não podem ser divididas, multiplicadas nem subtraídas, entretanto, o operador `+` pode ser usado nelas. Ele não efetua a adição, mas _concatena_, ou seja, junta duas _Strings_ em uma única _String_. O próximo exemplo produzirá a _String_ `"concatenate"`: 129 | 130 | ```js 131 | "con" + "cat" + "e" + "nate" 132 | ``` 133 | 134 | Existem outras maneiras de manipular as _Strings_, as quais serão discutidas quando chegarmos aos métodos no [Capítulo 4](./04-estruturas-de-dados.md#métodos). 135 | 136 | ## Operadores Unários 137 | 138 | Nem todos os operadores são símbolos, sendo que alguns são escritos como palavras. Um exemplo é o operador `typeof`, que produz um valor do tipo _String_ contendo o nome do tipo do valor que você está verificando. 139 | 140 | ```js 141 | console.log(typeof 4.5) 142 | // → number 143 | console.log(typeof "x") 144 | // → string 145 | ``` 146 | 147 | Nós vamos usar `console.log` nos códigos de exemplo para indicar que desejamos ver o resultado da avaliação de algo. Quando você executar tais códigos, o valor produzido será mostrado na tela, entretanto, a forma como ele será apresentado vai depender do ambiente JavaScript que você usar para rodar os códigos. 148 | 149 | Todos os operadores que vimos operavam em dois valores, mas `typeof` espera um único valor. Operadores que usam dois valores são chamados de operadores _binários_, enquanto que aqueles que recebem apenas um, são chamados de operadores _unários_. O operador `-` pode ser usado tanto como binário quanto como unário. 150 | 151 | ```js 152 | console.log(- (10 - 2)) 153 | // → -8 154 | ``` 155 | 156 | ## Valores _Booleanos_ 157 | 158 | Você frequentemente precisará de um valor para distinguir entre duas possibilidades, como por exemplo “sim” e “não”, ou “ligado” e “desligado”. Para isso, o JavaScript possui o tipo _Booleano_, que tem apenas dois valores: verdadeiro e falso (que são escritos como `true` e `false` respectivamente). 159 | 160 | ### Comparações 161 | 162 | Essa é uma maneira de produzir valores _Booleanos_: 163 | 164 | ```js 165 | console.log(3 > 2) 166 | // → true 167 | console.log(3 < 2) 168 | // → false 169 | ``` 170 | 171 | Os sinais `>` e `<` são tradicionalmente símbolos para representar “é maior que” e “é menor que” respectivamente. Eles são operadores binários, e o resultado da aplicação deles é um valor _Booleano_ que indica se a operação é verdadeira nesse caso. 172 | 173 | _Strings_ podem ser comparadas da mesma forma. 174 | 175 | ```js 176 | console.log("Aardvark" < "Zoroaster") 177 | // → true 178 | ``` 179 | 180 | A forma na qual as _Strings_ são ordenadas é mais ou menos alfabética. Letras maiúsculas serão sempre “menores” que as minúsculas, portanto, `“Z” < “a”` é verdadeiro. Além disso, caracteres não alfabéticos (!, -, e assim por diante) também são incluídos nessa ordenação. A comparação de fato, é baseada no padrão _Unicode_, que atribui um número para todos os caracteres que você possa precisar, incluindo caracteres do Grego, Árabe, Japonês, Tâmil e por aí vai. Possuir tais números é útil para armazenar as _Strings_ dentro do computador, pois faz com que seja possível representá-las como uma sequência de números. Quando comparamos _Strings_, o JavaScript inicia da esquerda para a direita, comparando os códigos numéricos dos caracteres um por um. 181 | 182 | Outros operadores parecidos são `>=` (maior que ou igual a), `<=` (menor que ou igual a), `==` (igual a) e `!=` (não igual a). 183 | 184 | ```js 185 | console.log("Itchy" != "Scratchy") 186 | // → true 187 | ``` 188 | 189 | Existe apenas um valor no JavaScript que não é igual a ele mesmo, que é o valor `NaN`. Ele significa _“not a number”_, que em português seria traduzido como “não é um número”. 190 | 191 | ```js 192 | console.log(NaN == NaN) 193 | // → false 194 | ``` 195 | 196 | `NaN` é supostamente usado para indicar o resultado de alguma operação que não tenha sentido e, por isso, ele não será igual ao resultado de quaisquer _outras_ operações sem sentido. 197 | 198 | ## Operadores Lógicos 199 | 200 | Existem também operadores que podem ser aplicados aos valores _Booleanos_. O JavaScript dá suporte a três operadores lógicos: _and_, _or_ e _not_, que podem ser traduzidos para o português como _e_, _ou_ e _não_. Eles podem ser usados para "pensar" de forma lógica sobre _Booleanos_. 201 | 202 | O operador `&&` representa o valor lógico _and_ ou, em português, _e_. Ele é um operador binário, e seu resultado é apenas verdadeiro se ambos os valores dados à ele forem verdadeiros. 203 | 204 | ```js 205 | console.log(true && false) 206 | // → false 207 | console.log(true && true) 208 | // → true 209 | ``` 210 | 211 | O operador `||` indica o valor lógico _or_ ou, em português, _ou_. Ele produz um valor verdadeiro se qualquer um dos valores dados à ele for verdadeiro. 212 | 213 | ```js 214 | console.log(false || true) 215 | // → true 216 | console.log(false || false) 217 | // → false 218 | ``` 219 | 220 | _Not_, em português _não_, é escrito usando um ponto de exclamação (`!`). Ele é um operador unário que inverte o valor que é dado à ele. Por exemplo, `!true` produz `false` e `!false` produz `true`. 221 | 222 | Quando misturamos esses operadores _Booleanos_ com operadores aritméticos e outros tipos de operadores, nem sempre é óbvio quando devemos usar ou não os parênteses. Na prática, você normalmente não terá problemas sabendo que, dos operadores que vimos até agora, `||` possui a menor precedência, depois vem o operador `&&`, em seguida vêm os operadores de comparação (`>`, `==`, etc) e, por último, quaisquer outros operadores. Essa ordem foi escolhida de tal forma que, em expressões típicas como o exemplo a seguir, poucos parênteses são realmente necessários: 223 | 224 | ```js 225 | 1 + 1 == 2 && 10 * 10 > 50 226 | ``` 227 | 228 | O último operador lógico que iremos discutir não é unário nem binário, mas _ternário_, operando em três valores. Ele é escrito usando um ponto de interrogação e dois pontos, como mostrado abaixo: 229 | 230 | ```js 231 | console.log(true ? 1 : 2); 232 | // → 1 233 | console.log(false ? 1 : 2); 234 | // → 2 235 | ``` 236 | 237 | Esse operador é chamado de operador _condicional_ (algumas vezes é chamado apenas de operador _ternário_, já que é o único operador desse tipo na linguagem). O valor presente à esquerda do ponto de interrogação “seleciona” qual dos outros dois valores será retornado. Quando ele for verdadeiro, o valor do meio é escolhido e, quando for falso, o valor à direita é retornado. 238 | 239 | ## Valores Indefinidos 240 | 241 | Existem dois valores especiais, `null` e `undefined`, que são usados para indicar a ausência de um valor com significado. Eles são valores por si sós, mas não carregam nenhum tipo de informação. 242 | 243 | Muitas operações na linguagem que não produzem um valor com significado (você verá alguns mais para frente) retornarão `undefined` simplesmente porque eles precisam retornar _algum_ valor. 244 | 245 | A diferença de significado entre `undefined` e `null` é um acidente que foi criado no design do JavaScript, e não faz muita diferença na maioria das vezes. Nos casos em que você deve realmente se preocupar com esses valores, recomendo tratá-los como valores idênticos (vamos falar mais sobre isso em breve). 246 | 247 | ## Conversão Automática de Tipo 248 | 249 | Na introdução, mencionei que o JavaScript tenta fazer o seu melhor para aceitar quase todos os programas que você fornecer, inclusive aqueles que fazem coisas bem estranhas. Isso pode ser demonstrado com as seguintes expressões: 250 | 251 | ```js 252 | console.log(8 * null) 253 | // → 0 254 | console.log("5" - 1) 255 | // → 4 256 | console.log("5" + 1) 257 | // → 51 258 | console.log("five" * 2) 259 | // → NaN 260 | console.log(false == 0) 261 | // → true 262 | ``` 263 | 264 | Quando um operador é aplicado a um tipo de valor “errado”, o JavaScript converterá, de forma silenciosa, esse valor para o tipo que ele desejar, usando uma série de regras que muitas vezes não é o que você deseja ou espera. Esse comportamento é chamado de _coerção de tipo_ (ou _conversão de tipo_). Portanto, na primeira expressão, `null` se torna `0` e, na segunda, a _String_ `"5"` se torna o número `5`. Já na terceira expressão, o operador `+` tenta efetuar uma concatenação de _String_ antes de tentar executar a adição numérica e, por isso, o número `1` é convertido para a _String_ `"1"`. 265 | 266 | Quando algo que não pode ser mapeado como um número de forma óbvia (tais como `"five"` ou `undefined`) é convertido para um número, o valor `NaN` é produzido. Quaisquer outras operações aritméticas realizadas com `NaN` continuam produzindo `NaN`, portanto, quando você perceber que está recebendo esse valor em algum lugar inesperado, procure por conversões de tipo acidentais. 267 | 268 | Quando comparamos valores do mesmo tipo usando o operador `==`, o resultado é fácil de se prever: você receberá verdadeiro quando ambos os valores forem o mesmo, exceto no caso de `NaN`. Por outro lado, quando os tipos forem diferentes, o JavaScript usa um conjunto de regras complicadas e confusas para determinar o que fazer, sendo que, na maioria dos casos, ele tenta apenas converter um dos valores para o mesmo tipo do outro valor. Entretanto, quando `null` ou `undefined` aparece em algum dos lados do operador, será produzido verdadeiro apenas se ambos os lados forem `null` ou `undefined`. 269 | 270 | ```js 271 | console.log(null == undefined); 272 | // → true 273 | console.log(null == 0); 274 | // → false 275 | ``` 276 | 277 | O último exemplo é um comportamento que normalmente é bastante útil. Quando quiser testar se um valor possui um valor real ao invés de `null` ou `undefined`, você pode simplesmente compará-lo a `null` com o operador `==` (ou `!=`). 278 | 279 | Mas e se você quiser testar se algo se refere ao valor preciso `false`? As regras de conversão de _Strings_ e números para valores _Booleanos_ afirmam que `0`, `NaN` e _Strings_ vazias contam como `false`, enquanto todos os outros valores contam como `true`. Por causa disso, expressões como `0 == false` e `"" == false` retornam `true`. Para casos assim, onde você **não** quer qualquer conversão automática de tipos acontecendo, existem dois tipos extras de operadores: `===` e `!==`. O primeiro testa se o valor é precisamente igual ao outro, e o segundo testa se ele não é precisamente igual. Então `"" === false` é falso como esperado. 280 | 281 | Usar os operadores de comparação de três caracteres defensivamente, para prevenir inesperadas conversões de tipo que o farão tropeçar, é algo que eu recomendo. Mas quando você tem certeza de que os tipos de ambos os lados serão iguais, ou que eles vão ser ambos `null`/`undefined`, não há problemas em usar os operadores curtos. 282 | 283 | ## O Curto-Circuito de && e || 284 | 285 | Os operadores lógicos `&&` e `||` tem uma maneira peculiar de lidar com valores de tipos diferentes. Eles vão converter o valor à sua esquerda para o tipo _Booleano_ a fim de decidir o que fazer, mas então, dependendo do operador e do resultado da conversão, eles ou retornam o valor à esquerda *original*, ou o valor à direita. 286 | 287 | O operador `||` vai retornar o valor à sua esquerda quando ele puder ser convertido em `true`, caso contrário, retorna o valor à sua direita. Ele faz a coisa certa para valores _Booleanos_, e vai fazer algo análogo para valores de outros tipos. Isso é muito útil, pois permite que o operador seja usado para retornar um determinado valor predefinido. 288 | 289 | ```javascript 290 | 291 | console.log(null || "user") 292 | // → user 293 | console.log("Karl" || "user") 294 | // → Karl 295 | 296 | ``` 297 | 298 | O operador `&&` trabalha similarmente, mas ao contrário. Quando o valor à sua esquerda é algo que se torne `false`, ele retorna o valor e caso contrário, ele retorna o valor à sua direita. 299 | 300 | Outra importante propriedade destes 2 operadores é que a expressão a sua direita é avaliada somente quando necessário. No caso de `true || X`, não importa o que `X` é - pode ser uma expressão que faça algo *terrível* - o resultado vai ser verdadeiro, e `X` nunca é avaliado. O mesmo acontece para `false && X`, que é falso, e vai ignorar `X`. 301 | 302 | ## Resumo 303 | 304 | Nós vimos 4 tipos de valores do JavaScript neste capítulo. Números, _Strings_, _Booleanos_ e valores indefinidos. 305 | 306 | Alguns valores são criados digitando seu nome (`true`, `null`) ou valores (13, `"abc"`). Você pode combinar e transformar valores com operadores. Nós vimos operadores binários para operações aritméticas (`+`, `-`, `*`, `/`, e `%`), um para concatenação de _String_ (`+`), comparação (`==`, `!=`, `===`, `!==`, `<`, `>`, `<=`, `>=`) e lógica (`&&`, `||`), assim como vários operadores unários (`-` para negativar um número, `!` para negar uma lógica, `typeof` para encontrar o tipo do valor) e o operador ternario (?:) para retornar um de dois valores, baseando-se em um terceiro valor. 307 | 308 | Isto lhe dá informação suficiente para usar o JavaScript como uma calculadora de bolso, mas não muito mais. O próximo capítulo vai começar a amarrar essas operações básicas conjuntamente dentro de programas básicos. 309 | -------------------------------------------------------------------------------- /chapters/06-a-vida-secreta-dos-objetos.md: -------------------------------------------------------------------------------- 1 | # A vida secreta dos objetos 2 | > "O problema com as linguagens orientadas a objeto é que elas têm tudo 3 | implícito no ambiente que elas carregam consigo. Você queria banana, mas o que 4 | você teve foi um gorila segurando a banana e toda a floresta." 5 | > `Joe Armstrong, entrevistado em Coders at Work` 6 | 7 | Quando um programador diz "objeto", isso é um termo carregado. Na minha 8 | profissão, objetos são a maneira de viver, o sujeito das guerras santas, e um 9 | jargão apaixonante que ainda não perdeu o seu poder. 10 | 11 | Para um estrangeiro, isso provavelmente é um pouco confuso. Vamos começar com 12 | uma rápida história dos objetos como constrtutores da programação. 13 | 14 | ## História 15 | Essa história, como a maioria das histórias de programação, começa com um 16 | problema de complexidade. A teoria é de que a complexidade pode ser 17 | administrada separando-a em pequenos compartimentos isolados um do outro. Esses 18 | compartimentos acabaram ganhando o nome de _objetos_. 19 | 20 | Um objeto é um escudo duro que esconde a complexidade grudenta dentro dele e nos apresenta pequenos conectores (como métodos) que apresentam uma interface 21 | para utilizarmos o objeto. A ideia é que a interface seja relativamente simples 22 | e toda as coisas complexas que vão dentro do objeto possam ser ignoradas 23 | enquanto se trabalha com ele. 24 | 25 | ![Uma interface simples pode esconder muita complexidade.](../img/object.jpg) 26 | 27 | Como exemplo, você pode imaginar um objeto que disponibiliza uma interface para 28 | uma determinada área na sua tela. Ele disponibiliza uma maneira de desenhar 29 | formas ou textos nessa área, mas esconde todos os detalhes de como essas formas 30 | são convertidos para os pixels que compõem a tela. Você teria um conjunto de 31 | métodos-`desenharCirculo`, por exemplo- e essas serão as únicas coisas que 32 | você precisa saber pra usar tal objeto. 33 | 34 | Essas ideias foram trabalhadas inicialmente por volta dos anos 70 e 80 e, nos 35 | anos 90, foram trazidas a tona por uma enorme onda _hype_-a revolução da 36 | programação orientada a objetos. De repente, existia uma enorme tribo de pessoas declarando que objetos eram a maneira correta de programar-e que qualquer coisa que não envolvesse objetos era uma loucura ultrapassada. 37 | 38 | Esse tipo de fanatismo produz um monte de bobagem impraticável, e desde então 39 | uma espécie de contra-revolução vem acontecendo. Em alguns círculos de 40 | desenvolvedores, os objetos têm uma péssima reputação hoje em dia. 41 | 42 | Eu prefiro olhar para esse problema de um ângulo prático, e não ideológico. 43 | Existem vários conceitos úteis, dentre eles um dos mais importantes é o 44 | _encapsulamento_ (distinguir complexidade interna e interface externa), que a 45 | cultura orientada a objetos tem popularizado. Vamos ver esses conceitos, pois 46 | eles valem a pena. 47 | 48 | Esse capítulo descreve uma pegada mais excêntrica do JavaScript com foco nos 49 | objetos e na forma como eles se relacionam com algumas técnicas clássicas de 50 | orientação a objetos. 51 | 52 | ## Métodos 53 | Métodos são propriedades simples que comportam valores de funções. Isso é um 54 | método simples: 55 | 56 | ```javascript 57 | var coelho = {}; 58 | coelho.diz = function(linha) { 59 | console.log("O coelho diz '" + linha + "'"); 60 | }; 61 | 62 | coelho.diz("Estou vivo."); 63 | // → O coelho diz 'Estou vivo.' 64 | ``` 65 | 66 | Normalmente um método precisa fazer alguma coisa com o objeto pelo qual ele 67 | foi chamado. Quando uma função é chamada como um método-visualizada como uma 68 | propriedade e imediatamente chamada, como em `objeto.metodo()`-a variável 69 | especial `this` no seu conteúdo vai apontar para o objeto pelo qual foi chamada. 70 | 71 | ```javascript 72 | function speak(line) { 73 | console.log("The " + this.type + " rabbit says '" + 74 | line + "'"); 75 | } 76 | var whiteRabbit = {type: "white", speak: speak}; 77 | var fatRabbit = {type: "fat", speak: speak}; 78 | 79 | whiteRabbit.speak("Oh my ears and whiskers, " + 80 | "how late it's getting!"); 81 | // → The white rabbit says 'Oh my ears and whiskers, how 82 | // late it's getting!' 83 | fatRabbit.speak("I could sure use a carrot right now."); 84 | // → The fat rabbit says 'I could sure use a carrot 85 | // right now.' 86 | ``` 87 | 88 | O código acima usa a palavra-chave `this` para dar a saída do tipo de coelho que está falando. Lembrando que ambos os métodos `apply` e `bind` podem usar o 89 | primeiro argumento para simular chamadas de métodos. Esse primeiro argumento, é 90 | na verdade, usado para passar um valor ao `this`. 91 | 92 | Existe um método parecido ao `apply` chamado `call`. Ele também chama a função 93 | na qual ele é um método e aceita argumentos normalmente, ao invés de um array. 94 | Assim como `apply` e `bind`, o `call` pode ser passado com um valor específico 95 | no `this`. 96 | 97 | ```javascript 98 | speak.apply(fatRabbit, ["Burp!"]); 99 | // → The fat rabbit says 'Burp!' 100 | speak.call({type: "old"}, "Oh my."); 101 | // → The old rabbit says 'Oh my.' 102 | ``` 103 | 104 | ## Prototypes 105 | Observe com atenção. 106 | 107 | ```javascript 108 | var empty = {}; 109 | console.log(empty.toString); 110 | // → function toString(){…} 111 | console.log(empty.toString()); 112 | // → [object Object] 113 | ``` 114 | 115 | Eu acabei de sacar uma propriedade de um objeto vazio. Mágica! 116 | 117 | Só que não. Eu venho ocultando algumas informações sobre como os objetos 118 | funcionam no JavaScript. Além de sua lista de propriedades, quase todos os 119 | objetos também possuem um _protótipo_, ou _prototype_. Um _prototype_ é outro objeto que é usado como fonte de _fallback_ para as propriedades. Quando um objeto recebe uma chamada em uma propriedade que ele não possui, seu _prototype_ designado para aquela propriedade será buscado, e então o _prototype_ daquele _prototype_ e assim por diante. 120 | 121 | Então quem é o _prototype_ de um objeto vazio? É o ancestral de todos os 122 | _prototypes_, a entidade por trás de quase todos os objetos, `Object.prototype`. 123 | 124 | ```javascript 125 | console.log(Object.getPrototypeOf({}) == 126 | Object.prototype); 127 | // → true 128 | console.log(Object.getPrototypeOf(Object.prototype)); 129 | // → null 130 | ``` 131 | 132 | A função `Object.getPrototypeOf` retorna o _prototype_ de um objeto como o esperado. 133 | 134 | As relações dos objetos JavaScript formam uma estrutura em forma de árvore, e na raiz dessa estrutura se encontra o `Object.prototype`. Ele fornece alguns métodos que estão presentes em todos os objetos, como o toString, que converte um objeto para uma representação em _string_. 135 | 136 | Muitos objetos não possuem o `Object.prototype` diretamente em seu _prototype_. Ao invés disso eles têm outro objeto que fornece suas propriedades padrão. Funções derivam do `Function.prototype`, e _arrays_ derivam do `Array.prototype`. 137 | 138 | ```javascript 139 | console.log(Object.getPrototypeOf(isNaN) == 140 | Function.prototype); 141 | // → true 142 | console.log(Object.getPrototypeOf([]) == 143 | Array.prototype); 144 | // → true 145 | ``` 146 | 147 | Por diversas vezes, o _prototype_ de um objeto também terá um _prototype_, dessa forma ele ainda fornecerá indiretamente métodos como `toString`. 148 | 149 | A função `Object.getPrototypeOf` obviamente retornarão o _prototype_ de um objeto. Você pode usar `Object.create` para criar um objeto com um _prototype_ específico. 150 | 151 | ```javascript 152 | var protoCoelho = { 153 | fala: function(linha) { 154 | console.log("O coelho " + this.tipo + " fala '" + 155 | linha + "'"); 156 | } 157 | }; 158 | var coelhoAssassino = Object.create(protoCoelho); 159 | coelhoAssassino.tipo = "assassino"; 160 | coelhoAssassino.fala("SKREEEE!"); 161 | // → O coelho assassino fala 'SKREEEE!' 162 | ``` 163 | 164 | ## Construtores 165 | 166 | A maneira mais conveniente de criar objetos que herdam algum _prototype_ compartilhado é usar um construtor. No JavaScript, chamar uma função precedida pela palavra-chave `new` vai fazer com que ela seja tratada como um construtor. O construtor terá sua variável `this` atrelada a um objeto novo, e a menos que ele explicite o retorno do valor de outro objeto, esse novo objeto será retornado a partir da chamada. 167 | 168 | Um objeto criado com `new` é chamado de _instância_ do construtor. 169 | 170 | Aqui está um construtor simples para coelhos. É uma conveção iniciar o nome de um construtor com letra maiúscula para que seja fácil destinguí-los das outras funções. 171 | 172 | ```javascript 173 | function Coelho(tipo) { 174 | this.tipo = tipo; 175 | } 176 | 177 | var coelhoAssassino = new Coelho("assassino"); 178 | var coelhoPreto = new Coelho("preto"); 179 | console.log(coelhoPreto.tipo); 180 | // → preto 181 | ``` 182 | 183 | Construtores (todas as funções, na verdade) pegam automaticamente uma propriedade chamada `prototype`, que por padrão possui um objeto vazio que deriva do `Object.prototype`. Toda instância criada com esse construtor terá esse objeto assim como seu _prototype_. Então, para adicionar um método `fala` aos coelhos criados com o construtor `Coelho`, nós podemos simplesmente fazer isso: 184 | 185 | ```javascript 186 | Coelho.prototype.fala = function(linha) { 187 | console.log("O coelho " + this.tipo + " fala '" + 188 | linha + "'"); 189 | }; 190 | coelhoPreto.fala("Doom..."); 191 | // → O coelho preto fala 'Doom...' 192 | ``` 193 | 194 | É importante notar a dinstinção entre a maneira que um _prototype_ é associado a um construtor (por sua propriedade _prototype_) e a maneira que objetos _têm_ um _prototype_ (que pode ser obtido com `Object.getPrototypeOf`). O _prototype_ propriamente dito de um construtor é `Function.prototype`, visto que os construtores são funções. Sua _propriedade_ `prototype` será o _prototype_ de instâncias criadas através dele mas não será seu _próprio prototype_. 195 | 196 | ## Definindo uma tabela 197 | 198 | Eu vou trabalhar sobre um exemplo ou pouco mais envolvido na tentativa de dar a você uma melhor ideia de polimorfismo, assim como de programação orientada a objetos em geral. O projeto é este: nós vamos escrever um programa que, dado um array de arrays de células de uma tabela, cria uma string que contém uma tabela bem formatada - significando que colunas são retas e linhas estão alinhadas. Algo dessa forma: 199 | 200 | ``` 201 | name height country 202 | ------------ ------ ------------- 203 | Kilimanjaro 5895 Tanzania 204 | Everest 8848 Nepal 205 | Mount Fuji 3776 Japan 206 | Mont Blanc 4808 Italy/France 207 | Vaalserberg 323 Netherlands 208 | Denali 6168 United States 209 | Popocatepetl 5465 Mexico 210 | ``` 211 | 212 | A forma que nosso sistema de construir tabelas vai funcionar é que a função construtora vai perguntar para cada célula quanto de altura e largura ela vai querer ter e então usar essa informação para determinar a largura das colunas e a altura das linhas. A função construtora vai então pedir para as células se desenharem no tamanho correto e montar o resultado dentro de uma string. 213 | 214 | O programa de *layout* vai comunicar com os objetos células através de uma interface bem definida. Dessa forma, os tipos de células que o programa suporta não está definida antecipadamente. Nós podemos adicionar novas células de estilo depois — por exemplo, células sublinhadas para cabeçalho — e se eles suportarem nossa interface, isso vai simplesmente, funcionar, sem exigir alterações no layout do programa. 215 | 216 | Esta é a interface: 217 | 218 | - `minHeight()` retorna um número indicando a altura mínima que esta célula necessita (em linhas). 219 | - `minWidth()` retorna um número indicando a largura mínima da célula (em caracteres). 220 | - `draw(width, height)` retorna um array de tamanho `height`, que contém uma série de strings que contém `width` caracteres de tamanho. Isso representa o conteúdo da célula. 221 | 222 | Irei fazer forte uso de métodos de ordem superior de array neste exemplo uma vez que isso é apropriado para essa abordagem. 223 | 224 | A primeira parte do programa calcula matrizes de largura e altura mínima para uma grade de células. 225 | 226 | ```js 227 | function rowHeights(rows) { 228 | return rows.map(function(row) { 229 | return row.reduce(function(max, cell) { 230 | return Math.max(max, cell.minHeight()); 231 | }, 0); 232 | }); 233 | } 234 | 235 | function colWidths(rows) { 236 | return rows[0].map(function(_, i) { 237 | return rows.reduce(function(max, row) { 238 | return Math.max(max, row[i].minWidth()); 239 | }, 0); 240 | }); 241 | } 242 | ``` 243 | 244 | Usar um nome de variável que se inicia com um *underscore* (`_`) ou consistir inteiramente em um simples underscore é uma forma de indicar (para leitores humanos) que este argumento não será usado. 245 | 246 | A função `rowHeights` não deve ser tão difícil de ser seguida. Ela usa `reduce` para computar a altura máxima de um array de células e envolve isso em um `map` para fazer isso em todas as linhas no array `rows`. 247 | 248 | As coisas são um pouco mais difíceis na função `colWidths` porque o array externo é um array de linhas, não de colunas. Não mencionei até agora que `map` (assim como `forEach`, `filter` e métodos de array similares) passam um segundo argumento à função fornecida: o índice do elemento atual. Mapeando os elementos da primeira linha e somente usando o segundo argumento da função de mapeamento, `colWidths` constrói um array com um elemento para cada índice da coluna. A chamada à `reduce` roda sobre o array `rows` exterior para cada índice e pega a largura da célula mais larga nesse índice. 249 | 250 | Aqui está o código para desenhar a tabela: 251 | 252 | ```js 253 | function drawTable(rows) { 254 | var heights = rowHeights(rows); 255 | var widths = colWidths(rows); 256 | 257 | function drawLine(blocks, lineNo) { 258 | return blocks.map(function(block) { 259 | return block[lineNo]; 260 | }).join(" "); 261 | } 262 | 263 | function drawRow(row, rowNum) { 264 | var blocks = row.map(function(cell, colNum) { 265 | return cell.draw(widths[colNum], heights[rowNum]); 266 | }); 267 | return blocks[0].map(function(_, lineNo) { 268 | return drawLine(blocks, lineNo); 269 | }).join("\n"); 270 | } 271 | 272 | return rows.map(drawRow).join("\n"); 273 | } 274 | ``` 275 | 276 | A função `drawTable` usa a função interna `drawRow` para desenhar todas as linhas e então as junta com caracteres *newline* (nova linha). 277 | 278 | A função `drawRow` primeiro converte os objetos célula na linha em *blocos*, que são arrays representando o conteúdo das células, divididos por linha. Uma célula simples contendo apenas o número 3776 deve ser representada por um array com um único elemento como `["3776"]`, onde uma célula sublinhada deve conter duas linhas e ser representada pelo array `["name", "----"]`. 279 | 280 | Os blocos para uma linha, que devem todos ter a mesma largura, devem aparecer próximos um ao outro na saída final. A segunda chamada a `map` em `drawRow` constrói essa saída linha por linha mapeando sobre as linhas do bloco mais à esquerda e, para cada uma delas, coletando uma linha que expande a tabela para sua largura máxima. Essas linhas são então juntadas com caracteres *newline* para fornecer a linha completa e ser o valor retornado de `drawRow`. 281 | 282 | A função `drawLine` extrai linhas que devem aparecer próximas uma a outra a partir de um array de blocos e as junta com um caracter espaço para criar o espaço de um caracter entre as colunas da tabela. 283 | 284 | Agora vamos escrever o construtor para células que contenham texto, implementando a interface para as células da tabela. O construtor divide a linha em um array de linhas usando o método string `split`, que corta uma string em cada ocorrência do seu argumento e retorna um array com as partes. O método `minWidth` encontra a linha com maior largura nesse array. 285 | 286 | ```js 287 | function repeat(string, times) { 288 | var result = ""; 289 | for (var i = 0; i < times; i++) 290 | result += string; 291 | return result; 292 | } 293 | 294 | function TextCell(text) { 295 | this.text = text.split("\n"); 296 | } 297 | TextCell.prototype.minWidth = function() { 298 | return this.text.reduce(function(width, line) { 299 | return Math.max(width, line.length); 300 | }, 0); 301 | }; 302 | TextCell.prototype.minHeight = function() { 303 | return this.text.length; 304 | }; 305 | TextCell.prototype.draw = function(width, height) { 306 | var result = []; 307 | for (var i = 0; i < height; i++) { 308 | var line = this.text[i] || ""; 309 | result.push(line + repeat(" ", width - line.length)); 310 | } 311 | return result; 312 | }; 313 | ``` 314 | 315 | O código usa uma função auxiliar chamada `repeat`, que constrói uma linha na qual o valor é um argumento `string` repetido `times` número de vezes. O método `draw` usa isso e adiciona "preenchimento" para as linhas assim todas vão ter o tamanho requerido. 316 | 317 | Vamos testar tudo que construímos e criar um tabuleiro de damas 5 x 5. 318 | 319 | ```js 320 | var rows = []; 321 | for (var i = 0; i < 5; i++) { 322 | var row = []; 323 | for (var j = 0; j < 5; j++) { 324 | if ((j + i) % 2 == 0) 325 | row.push(new TextCell("##")); 326 | else 327 | row.push(new TextCell(" ")); 328 | } 329 | rows.push(row); 330 | } 331 | console.log(drawTable(rows)); 332 | // → ## ## ## 333 | // ## ## 334 | // ## ## ## 335 | // ## ## 336 | // ## ## ## 337 | ``` 338 | 339 | Funciona! Mas apesar de todas as células terem o mesmo tamanho, o código do layout da tabela não faz nada realmente interessante. 340 | 341 | Os dados fonte para a tabela de montanhas que estamos tentando construir estão disponíveis na variável `MOUNTAINS` na *sandbox* e também [neste arquivo](http://eloquentjavascript.net/code/mountains.js) em nosso website. 342 | 343 | Vamos querer destacar a linha do topo, que contém o nome das colunas, sublinhando as células com uma série de caracteres *traço*. Sem problemas — nós simplesmente escrevemos um tipo de célula que manipula o sublinhado. 344 | 345 | ```js 346 | function UnderlinedCell(inner) { 347 | this.inner = inner; 348 | }; 349 | UnderlinedCell.prototype.minWidth = function() { 350 | return this.inner.minWidth(); 351 | }; 352 | UnderlinedCell.prototype.minHeight = function() { 353 | return this.inner.minHeight() + 1; 354 | }; 355 | UnderlinedCell.prototype.draw = function(width, height) { 356 | return this.inner.draw(width, height - 1) 357 | .concat([repeat("-", width)]); 358 | }; 359 | ``` 360 | 361 | Uma célula sublinhada *contém* outra célula. Ela reporta seu tamanho mínimo sendo o mesmo que da sua célula interna (chamando os métodos `minWidth` e `minHeight` desta célula) mas adicionando um à largura para contar o espaço usado pelo sublinhado. 362 | 363 | Desenhar essa célula é bem simples - nós pegamos o conteúdo da célula interna e concatenamos uma simples linha preenchida com traços a ela. 364 | 365 | Tendo um mecanismo de sublinhamento, nós podemos agora escrever uma função que constrói uma grade de células a partir do conjunto de dados. 366 | 367 | ```js 368 | function dataTable(data) { 369 | var keys = Object.keys(data[0]); 370 | var headers = keys.map(function(name) { 371 | return new UnderlinedCell(new TextCell(name)); 372 | }); 373 | var body = data.map(function(row) { 374 | return keys.map(function(name) { 375 | return new TextCell(String(row[name])); 376 | }); 377 | }); 378 | return [headers].concat(body); 379 | } 380 | 381 | console.log(drawTable(dataTable(MOUNTAINS))); 382 | // → name height country 383 | // ------------ ------ ------------- 384 | // Kilimanjaro 5895 Tanzania 385 | // … etcetera 386 | ``` 387 | 388 | A função padrão `Object.keys` retorna um array com nomes de propriedades de um objeto. A linha do topo da tabela deve conter células sublinhadas que dão os nomes das colunas. Abaixo disso, os valores de todos os objetos no conjunto de dados aparecem como células normais - nós os extraímos mapeando sobre o array `keys` de modo que tenhamos certeza que a ordem das células é a mesma em todas as linhas. 389 | 390 | A tabela resultante se assemelha ao exemplo mostrado anteriormente, exceto que ela não alinha os números à direita na coluna `height`. Vamos chegar nessa parte em um instante. 391 | 392 | ## Getters and Setters 393 | 394 | Quando especificamos uma interface, é possível incluir propriedades que não são métodos. Poderíamos ter definido `minHeight` e `minWidth` para simplesmente conter números. Mas isso teria exigido de nós computá-los no construtor, o que adicionaria código que não é estritamente relevante para *construção* do objeto. Isso pode causar problemas se, por exemplo, a célula interior de uma célula exterior mudou, onde nesse ponto o tamanho da célula sublinhada também deve mudar. 395 | 396 | Isso tem levado algumas pessoas a adotarem um princípio de nunca incluírem propriedades *nonmethod* em interfaces. Ao invés de acessarem diretamente o valor da propriedade, eles usam métodos `getSomething` e `setSomething` para ler e escrever propriedades. Esta abordagem tem a parte negativa de que você irá acabar escrevendo - e lendo - muitos métodos adicionais. 397 | 398 | Felizmente, o JavaScript fornece uma técnica que fornece o melhor de ambos os mundos. Nós podemos especificar propriedades que, do lado de fora, parecem propriedades normais mas secretamente tem métodos associados a elas. 399 | 400 | ```js 401 | var pile = { 402 | elements: ["eggshell", "orange peel", "worm"], 403 | get height() { 404 | return this.elements.length; 405 | }, 406 | set height(value) { 407 | console.log("Ignoring attempt to set height to", value); 408 | } 409 | }; 410 | 411 | console.log(pile.height); 412 | // → 3 413 | pile.height = 100; 414 | // → Ignoring attempt to set height to 100 415 | ``` 416 | 417 | Em um objeto literal, a notação `get` ou `set` para propriedades permite que você especifique uma função a ser executada quando a propriedade for lida ou escrita. Você pode também adicionar tal propriedade em um objeto existente, por exemplo um protótipo, usando a função `Object.defineProperty` (que nós previamente usamos para criar propriedades não enumeráveis). 418 | 419 | ```js 420 | Object.defineProperty(TextCell.prototype, "heightProp", { 421 | get: function() { return this.text.length; } 422 | }); 423 | 424 | var cell = new TextCell("no\nway"); 425 | console.log(cell.heightProp); 426 | // → 2 427 | cell.heightProp = 100; 428 | console.log(cell.heightProp); 429 | // → 2 430 | ``` 431 | 432 | Você pode usar a propriedade similar `set`, no objeto passado à `defineProperty`, para especificar um método *setter*. Quando um *getter* é definido mas um *setter* não, escrever nessa propriedade é algo simplesmente ignorado. 433 | 434 | ## Herança 435 | 436 | Nós não estamos prontos com nosso exercício de layout de tabela. Ela deve ajudar na leitura de números alinhados à direita em colunas. Nós devemos criar outra tipo de célula como `TextCell`, mas ao invés de dar espaço nas linhas do lado direito, vamos espaçá-las do lado esquerdo que irá alinhas à direita. 437 | 438 | Podemos simplesmente construir um novo construtor com todos os três métodos em seu protótipo. Mas protótipos podem ter seus próprios protótipos, e isso nos permite fazer algo inteligente. 439 | 440 | ```js 441 | function RTextCell(text) { 442 | TextCell.call(this, text); 443 | } 444 | RTextCell.prototype = Object.create(TextCell.prototype); 445 | RTextCell.prototype.draw = function(width, height) { 446 | var result = []; 447 | for (var i = 0; i < height; i++) { 448 | var line = this.text[i] || ""; 449 | result.push(repeat(" ", width - line.length) + line); 450 | } 451 | return result; 452 | }; 453 | ``` 454 | 455 | Nós reusamos o construtor e os métodos `minHeight` e `minWidth` de `TextCell`. Um `RTextCell` é agora basicamente equivalente a `TextCell`, exceto que seu método `draw` contém uma função diferente. 456 | 457 | Este padrão é chamado *herança*. Isso nos permite construir tipos de dados levemente diferentes a partir de tipos de dados existentes com relativamente pouco esforço. Tipicamente, o novo construtor vai chamar o antigo construtor (usando o método `call` para ser capaz de dar a ele o novo objeto assim como o seu valor `this`). Uma vez que esse construtor tenha sido chamado, nós podemos assumir que todos os campos que o tipo do antigo objeto supostamente contém foram adicionados. Nós organizamos para que o protótipo do construtor derive do antigo protótipo, então as instâncias deste tipo também vão acesso às propriedades deste protótipo. Finalmente, nós podemos sobrescrever algumas das propriedades adicionando-as ao nosso novo protótipo. 458 | 459 | Agora, se nós ajustarmos sutilmente a função `dataTable` para usar `RTextCell` para as células cujo valor é um número, vamos obter a tabela que estávamos buscando. 460 | 461 | ```js 462 | function dataTable(data) { 463 | var keys = Object.keys(data[0]); 464 | var headers = keys.map(function(name) { 465 | return new UnderlinedCell(new TextCell(name)); 466 | }); 467 | var body = data.map(function(row) { 468 | return keys.map(function(name) { 469 | var value = row[name]; 470 | // This was changed: 471 | if (typeof value == "number") 472 | return new RTextCell(String(value)); 473 | else 474 | return new TextCell(String(value)); 475 | }); 476 | }); 477 | return [headers].concat(body); 478 | } 479 | 480 | console.log(drawTable(dataTable(MOUNTAINS))); 481 | // → … beautifully aligned table 482 | ``` 483 | 484 | Herança é uma parte fundamental da orientação a objetos tradicional, ao lado de encapsulamento e polimorfismo. Mas enquanto os dois últimos sejam agora geralmente considerados como ideias brilhantes, herança é algo controverso. 485 | 486 | A principal razão para isso é que este tópico é geralmente confundido com polimorfismo, vendido como uma ferramenta mais poderosa do que realmente é, e subsequentemente usado em excesso de diversas horríveis formas. Onde encapsulamento e polimorfismo podem ser usados para *separar* pedaços de código de cada um, reduzindo o emaranhamento de todo o programa, herança fundamentalmente vincula os tipos, criando *mais* emaranhados. 487 | 488 | Você pode ter polimorfismo sem herança, como nós vimos. Eu não vou dizer para você evitar herança completamente. Eu a uso regularmente em meus programas. Mas você deve vê-la como um leve truque desonesto que vai ajudá-lo a definir novos tipos com menos código, não como um grande princípio de organização de código. Uma forma mais apropriada de extender tipos é através da composição, como `UnderlinedCell` constrói em outra célula simplesmente armazenando-a em uma propriedade e um método posterior a chama nos seus próprios métodos. 489 | 490 | ## O operador `instanceof` 491 | 492 | Ocasionalmente é útil saber se um objeto foi derivado de um construtor em específico. Para isso, o JavaScript fornece um operador binário chamado `instaceof`. 493 | 494 | ```js 495 | console.log(new RTextCell("A") instanceof RTextCell); 496 | // → true 497 | console.log(new RTextCell("A") instanceof TextCell); 498 | // → true 499 | console.log(new TextCell("A") instanceof RTextCell); 500 | // → false 501 | console.log([1] instanceof Array); 502 | // → true 503 | ``` 504 | 505 | O operador vai olhar através dos tipos herdados. Um `RTextCell` é uma instância de `TextCell` porque `RTextCell.prototype` deriva de `TextCell.prototype`. O operador pode ser aplicado a construtores padrão como `Array`. Praticamente todos os objetos são uma instância de `Object`. 506 | 507 | ## Resumo 508 | 509 | Então objetos são mais complicados do que inicialmente eu os retratei. Eles tem protótipos, que são outros objetos, e vão agir como se tivessem propriedades que eles não tem caso seu protótipo tenha essa propriedade. Objetos simples tem `Object.prototype` como seus protótipos. 510 | 511 | Construtores, que são funções cujos nomes usualmente iniciam com uma letra maiúscula, podem ser usador com o operador `new` para criar objetos. O protótipo do novo objeto será o objeto encontrado na propriedade `prototype` da função construtora. Você pode fazer bom uso disso adicionando propriedades que todos os valores de um tipo compartilham em seus protótipos. O operador `instanceof` pode, dado um objeto e um construtor, dizer se o objeto é uma instância deste construtor. 512 | 513 | Algo útil a se fazer com objetos é especificar uma interface para eles e dizer para todos quer irão supostamente conversar com seu objeto a fazer isso somente por essa interface. O resto dos detalhes que constroem seu objeto estão agora *encapsulados*, escondidos atrás da interface. 514 | 515 | Uma vez que você esteja conversando em termos de interfaces, quem diz que apenas um tipo de objeto pode implementar essa interface? Ter diferentes objetos expondo a mesma interface é chamado de *polimorfismo*. Isso é muito útil. 516 | 517 | Quando implementando vários tipos que diferem apenas em alguns detalhes, pode ser útil simplesmente criar o protótipo do seu novo tipo derivando do protótipo do seu antigo tipo e ter seu novo construtor chamando o antigo. Isso lhe dá um tipo similar de objeto ao antigo mas que permite que você adicione ou sobrescreva propriedades quando necessário. 518 | 519 | ## Exercícios 520 | 521 | ### Um tipo de vetor 522 | 523 | Escreva um construtor `Vector` que represente um vetor em duas dimensões do espaço. Ele recebe os parâmetros `x` e `y` (números), que deve salvar em propriedades de mesmo nome. 524 | 525 | Dê ao protótipo de `Vector` dois métodos, `plus` e `minus`, que pegam outro vetor como parâmetro e retornam um novo vetor que tem a soma ou diferença dos valores `x` e `y` dos dois vetores (o vetor que está em `this` e o passado no parâmetro). 526 | 527 | Adicione uma propriedade getter `length` ao protótipo que calcula o tamanho do vetor - isto é, a distância do ponto (`x, y`) até a origem (0,0). 528 | 529 | ```js 530 | // Your code here. 531 | 532 | console.log(new Vector(1, 2).plus(new Vector(2, 3))); 533 | // → Vector{x: 3, y: 5} 534 | console.log(new Vector(1, 2).minus(new Vector(2, 3))); 535 | // → Vector{x: -1, y: -1} 536 | console.log(new Vector(3, 4).length); 537 | // → 5 538 | ``` 539 | 540 | **Dicas** 541 | 542 | Sua solução pode seguir o padrão do construtor `Rabbit` deste capítulo de forma bem semelhante. 543 | 544 | Adicionar uma propriedade getter ao construtor pode ser feita com a função `Object.defineProperty`. Para calcular a distância do ponto `(0, 0)` até `(x, y)` você pode usar o teorema de Pitágoras, que diz que o quadrado da distância que estamos procurando é igual ao quadrado da coordenada x mais o quadrado da coordenada y. Assim, `√(x2 + y2)` é o número que você quer, e `Math.sqrt` é o caminho para você calcular a raiz quadrada no JavaScript. 545 | 546 | ## Outra célula 547 | 548 | Implemente uma célula do tipo `StretchCell(inner, width, height)` que se adeque a [interface da célula da tabela](#definindo-uma-tabela) descrita anteriormente neste capítulo. Ela deve envolver outra célula (como `UnderlinedCell` faz) e assegurar que a célula resultante tem pelo menos a largura (`width`) e altura (`height`) especificada, mesmo se a célula interior for naturalmente menor. 549 | 550 | ```js 551 | // Your code here. 552 | 553 | var sc = new StretchCell(new TextCell("abc"), 1, 2); 554 | console.log(sc.minWidth()); 555 | // → 3 556 | console.log(sc.minHeight()); 557 | // → 2 558 | console.log(sc.draw(3, 2)); 559 | // → ["abc", " "] 560 | ``` 561 | 562 | **Dicas** 563 | 564 | Você vai ter que armazenar os 3 argumentos construtores na instância do objeto. Os métodos `minWidth` e `minHeight` devem chamar através dos métodos correspondentes na célula interna (`inner`), mas assegure-se que nenhum número menor que o tamanho dado é retornado (possivelmente usando `Math.max`). 565 | 566 | Não se esqueça de adicionar um método `draw` que simplesmente encaminha a chamada para a célula interior. 567 | 568 | ### Interface sequencial 569 | 570 | Projete uma *interface* que abstraia interações sobre uma coleção de valores. Um objeto que fornece esta interface representa uma sequência, e a interface deve de alguma forma tornar possível para o código que usa este objeto iterar sobre uma sequência, olhando para o valor dos elementos de que ela é composta e tendo alguma forma de saber quando o fim da sequência foi atingido. 571 | 572 | Quando você tiver especificado sua interface, tente escrever uma função `logFive` que pega um objeto sequencial e chama `console.log` para seus primeiros 5 elementos - ou menos, se a sequência tiver menos do que cinco elementos. 573 | 574 | Então implemente um tipo de objeto `ArraySeq` que envolve um array e permite interação sobre o array usando a interface que você desenvolveu. Implemente outro tipo de objeto `RangeSeq` que itera sobre um intervalo de inteiros (recebendo os argumentos `from` e `to` em seu construtor). 575 | 576 | ```js 577 | // Your code here. 578 | 579 | logFive(new ArraySeq([1, 2])); 580 | // → 1 581 | // → 2 582 | logFive(new RangeSeq(100, 1000)); 583 | // → 100 584 | // → 101 585 | // → 102 586 | // → 103 587 | // → 104 588 | ``` 589 | 590 | **Dicas** 591 | 592 | Uma forma de resolver isso é fornecendo objetos sequenciais *state*, que significa que suas propriedades são alteradas no seu processo de uso. Você pode armazenar um contador que indica quão longe o objeto sequenciais avançaram. 593 | 594 | Sua interface vai precisar expor ao menos uma forma de pegar o próximo elemento e encontrar se a iteração já chegou no fim da sequencia. É tentador fazer isso em um método, `next`, que retorna `null` ou `undefined` quando a sequência chegar ao fim. Mas agora você tem um problema quando a sequência realmente tiver `null`. Então um método separado (ou uma propriedade getter) para descobrir se o fim foi alcançado é provavelmente preferível. 595 | 596 | Outra solução é evitar mudar o estado do objeto. Você pode expor um método para pegar o elemento atual (sem o auxílio de nenhum contador) e outro para pegar uma nova sequência que representa os elementos restantes depois do atual (ou um valor especial se o fim da sequência tiver sido atingido). Isso é bem elegante - um valor sequencial vai "permanecer ele mesmo" mesmo depois de ter sido usado e pode ser compartilhado com outro código sem a preocupação sobre o que pode acontecer com ele. Isso é, infelizmente, algo um pouco ineficiente numa linguagem como JavaScript porque envolve criar vários objetos durante a iteração. 597 | -------------------------------------------------------------------------------- /chapters/08-erros-e-manipulacao-de-erros.md: -------------------------------------------------------------------------------- 1 | # Bugs e manipulação de erros 2 | 3 | > “Debugar é duas vezes mais difícil do que escrever código. Portanto, se você escrever código da maneira mais inteligente possível, por definição, você não é inteligente o suficiente para debugá-lo.” 4 | > — Brian Kernighan and P.J. Plauger, The Elements of Programming Style 5 | 6 | > Yuan-Ma havia escrito um pequeno programa onde utilizou muitas variáveis globais e atalhos que faziam a qualidade do seu código inferior. Lendo o programa, um estudante perguntou: “Você nos avisou para não usar essas técnicas e mesmo assim as encontro no seu programa. Como pode isso?”. O mestre respondeu: “Não há necessidade de se buscar uma mangueira de água quando a casa não está em chamas.” 7 | > — Master Yuan-Ma, The Book of Programming 8 | 9 | Programas são pensamentos “cristalizados”. Algumas vezes, esses pensamentos são confusos e erros podem ser inseridos quando convertemos pensamentos em código, resultando em um programa com falhas. 10 | 11 | Falhas em um programa são normalmente chamadas de *bugs*, e podem ser causadas por erros inseridos pelo programador ou problemas em outros sistemas que a aplicação interage. Alguns *bugs* são imediatamente aparentes, enquanto outros são sutis e podem ficar escondidos em um sistema por anos. 12 | 13 | Muitas vezes os problemas aparecem quando um programa executa de uma forma que o programador não considerou originalmente. Às vezes, tais situações são inevitáveis. Quando o usuário insere um dado inválido, isso faz com que a aplicação fique em uma situação difícil. Tais situações devem ser antecipadas e tratadas de alguma maneira. 14 | 15 | ## Erros do programador 16 | 17 | O nosso objetivo é simples quando se trata de erros do programador. Devemos encontrá-los e corrigi-los. Tais erros podem variar entre erros simples que faz o computador reclamar assim que ele tenta executar o programa ou erros sutis causado por uma compreensão errada da lógica do programa levando a resultados incorretos, podendo ser constante ou em apenas algumas condições específicas. Esse último tipo de erros pode levar semanas para ter um diagnóstico correto. 18 | 19 | O nível de ajuda que as linguagens oferecem para encontrar os erros variam bastante. Isso não é nenhuma surpresa pois o JavaScript está no "quase não ajuda em nada" no final dessa escala. Algumas linguagens exigem os tipos de todas as suas variáveis e expressões antes mesmo de executar; isso dá a possibilidade do programa nos dizer imediatamente quando um tipo é usado de forma incorreta. 20 | JavaScript considera os tipos somente na execução do programa e mesmo assim ele permite que você faça algumas coisas visivelmente absurdas sem dar nenhum tipo de aviso como por exemplo: `x = true "macaco" *`. 21 | 22 | Há algumas coisas que o JavaScript não se queixa. Mas escrever um programa que é sintaticamente incorreto faz com que ele nem execute e dispare um erro imediatamente. 23 | Existem outras coisas como, chamar algo que não é uma função ou procurar uma propriedade em um valor indefinido, isso causa um erro a ser relatado somente quando o programa entrar em execução e encontrar essa ação que não tem sentido. 24 | 25 | Mas muitas das vezes um cálculo absurdo pode simplesmente produzir um `NaN` (não um número) ou um valor indefinido. O programa irá continuar alegremente convencido de que está fazendo algo correto. O erro vai se manifestar somente mais tarde, depois que o valor falso passou por várias funções. Não que isso venha desencadear um erro em tudo, mas isso pode silenciosamente causar uma série de saídas erradas. Encontrar a fonte de tais problemas são considerados difíceis. 26 | 27 | O processo de encontrar erros (bugs) nos programas é chamado de depuração. 28 | 29 | # Modo estrito 30 | 31 | JavaScript pode ser feito de uma forma mais rigorosa, permitindo que o modo seja estrito. Para obter esse modo basta inserir uma string `"use strict"` na parte superior de um arquivo ou no corpo de uma função. Veja o exemplo: 32 | 33 | ````js 34 | function canYouSpotTheProblem() { 35 | "use strict"; 36 | for (counter = 0; counter < 10; counter++) 37 | console.log("Happy happy"); 38 | } 39 | 40 | canYouSpotTheProblem(); 41 | // → ReferenceError: counter is not defined 42 | ```` 43 | 44 | Normalmente, quando você esquece de colocar `var` na frente de sua variável como acontece no exemplo, o JavaScript cria uma variável global para utilizá-la, no entanto no modo estrito um erro é relatado. Isto é muito útil. Porém deve-se notar que isso não funciona quando a variável em questão já existe como uma variável global, isso é apenas para atribuição ou criação. 45 | 46 | Outra mudança no modo estrito é que esta ligação tem o valor `undefined` para funções que não são chamadas como métodos. Ao fazer tal chamada fora do modo estrito a referência do objeto é do escopo global. Então se você acidentalmente chamar um método ou um construtor incorretamente no modo estrito o JavaScript produzirá um erro assim que ele tentar ler algo com isso ao invés de seguir trabalhando normalmente com a criação e leitura de variáveis globais no objeto global. 47 | 48 | Por exemplo, considere o seguinte código que chama um construtor sem a nova palavra-chave, na qual seu objeto não vai se referir a um objeto recém-construído: 49 | 50 | ````js 51 | function Person(name) { this.name = name; } 52 | var ferdinand = Person("Ferdinand"); // oops 53 | console.log(name); 54 | // → Ferdinand 55 | ```` 56 | 57 | Assim, a falsa chamada para `Person` foi bem sucedida, mas retornou um valor indefinido e criou uma variável global. No modo estrito, o resultado é diferente. 58 | 59 | ````js 60 | "use strict"; 61 | function Person(name) { this.name = name; } 62 | // Oops, forgot 'new' 63 | var ferdinand = Person("Ferdinand"); 64 | // → TypeError: Cannot set property 'name' of undefined 65 | ```` 66 | 67 | Somos imediatamente informados de que algo está errado. Isso é útil. 68 | 69 | Existe mais coisas no modo estrito. Ele não permite dar a uma função vários parâmetros com o mesmo nome e remove totalmente certas características problemáticas da linguagem. 70 | 71 | Em suma, colocando um `"use strict"` no topo do seu programa não irá causar frustrações mas vai ajudar a detectar problemas. 72 | 73 | ## Testando 74 | 75 | A linguagem não vai nos ajudar muito a encontrar erros, nós vamos ter que encontrá-los da maneira mais difícil: executando o programa e analisando se o comportamento está correto. 76 | 77 | Fazer sempre testes manualmente é uma maneira insana de conduzir-se. Felizmente é possível muitas das vezes escrever um segundo programa que automatiza o teste do seu programa atual. 78 | 79 | Como por exemplo, vamos construir um objeto `Vector`: 80 | 81 | ````js 82 | function Vector(x, y) { 83 | this.x = x; 84 | this.y = y; 85 | } 86 | 87 | Vector.prototype.plus = function(other) { 88 | return new Vector(this.x + other.x, this.y + other.y); 89 | }; 90 | ```` 91 | 92 | Vamos escrever um programa para verificar se a nossa implementação do objeto `Vector` funciona como o esperado. Então cada vez que mudarmos a implementação o programa de teste é executado, de modo que fiquemos razoavelmente confiantes de que nós não quebramos nada. Quando adicionarmos uma funcionalidade extra (por exemplo, um novo método) no objeto `Vector`, também devemos adicionar testes para o novo recurso. 93 | 94 | ````js 95 | function testVector() { 96 | var p1 = new Vector(10, 20); 97 | var p2 = new Vector(-10, 5); 98 | var p3 = p1.plus(p2); 99 | 100 | if (p1.x !== 10) return "fail: x property"; 101 | if (p1.y !== 20) return "fail: y property"; 102 | if (p2.x !== -10) return "fail: negative x property"; 103 | if (p3.x !== 0) return "fail: x from plus"; 104 | if (p3.y !== 25) return "fail: y from plus"; 105 | return "everything ok"; 106 | } 107 | console.log(testVector()); 108 | // → everything ok 109 | ```` 110 | 111 | Escrevendo testes como este tende a parecer um pouco repetitivo e um código estranho. Felizmente existem opções de software que ajudam a construir e executar coleções de testes (suites de teste), fornecendo uma linguagem (na forma de funções e métodos) adequada para expressar os testes e emitir informações informativas de quando um teste falhou. Isto é chamados de estruturas de teste. 112 | 113 | ## Depuração 114 | 115 | Você consegue perceber que há algo errado com o seu programa quando ele está se comportando mal ou produzindo erros; o próximo passo é descobrir qual é o problema. 116 | 117 | Às vezes é óbvio. A mensagem de erro vai apontar para a linha específica; e se você olhar para a descrição do erro e para linha de código muitas vezes você irá entender o problema. 118 | 119 | Mas nem sempre é assim. Às vezes a linha que desencadeou o problema é simplesmente o primeiro lugar onde um valor falso foi produzido e que em outros lugares foi usado de uma forma incorreta ou as vezes não há nenhuma mensagem de erro, apenas um resultado inválido. Se você tentou resolver os exercícios nos capítulos anteriores você provavelmente já experimentou tais situações. 120 | 121 | O exemplo seguinte tenta converter um número inteiro para uma cadeia em qualquer base (decimal, binário, e assim por diante), para se livrar do último dígito escolhemos o último dígito repetidamente e em seguida dividimos. Mas a saída produzida sugere que ele tem um bug. 122 | 123 | ````js 124 | function numberToString(n, base) { 125 | var result = "", sign = ""; 126 | if (n < 0) { 127 | sign = "-"; 128 | n = -n; 129 | } 130 | do { 131 | result = String(n % base) + result; 132 | n /= base; 133 | } while (n > 0); 134 | return sign + result; 135 | } 136 | console.log(numberToString(13, 10)); 137 | // → 1.5e-3231.3e-3221.3e-3211.3e-3201.3e-3191.3e-3181.3… 138 | ```` 139 | 140 | Mesmo se você já viu o problema e fingiu por um momento que você não viu. Sabemos que o nosso programa não está funcionando corretamente e queremos descobrir o porquê. 141 | 142 | Esta é a hora onde você deve resistir à tentação de começar a fazer mudanças aleatórias no código. Em vez disso pense, analise o que está acontecendo e chegue a uma teoria de por que isso pode estar acontecendo. Então faça observações adicionais para testar esta teoria ou se você ainda não tem uma teoria, faça observações adicionais que podem ajudá-lo. 143 | 144 | Colocar algumas chamadas `console.log` estratégicas no programa é uma boa maneira de obter informações adicionais sobre o que o programa está fazendo. Neste caso queremos tomar os `n` valores de 13, 1 até 0. Vamos descrever o seu valor no início do loop. 145 | 146 | ```` 147 | 13 148 | 1.3 149 | 0.13 150 | 0.013 151 | … 152 | 1.5e-323 153 | ```` 154 | 155 | Certo. Dividindo 13 por 10 não produz um número inteiro. Em vez de `n / = base` o que nós realmente queremos é `n = Math.floor (n / base)` de modo que o número está devidamente deslocando-se para a direita. 156 | 157 | Uma alternativa para o uso do `console.log` é usar os recursos de depuração do seu browser. Navegadores modernos vêm com a capacidade de definir um ponto de interrupção em uma linha específica de seu código. Isso fará com que a execução do programa faz uma pausa a cada vez que a linha com o ponto de interrupção é atingido. Isso permite que você inspecione os valores das variáveis nesse ponto. Eu não vou entrar em detalhes aqui pois depuradores diferem de navegador para navegador, mas vale a pena olhar as ferramentas de desenvolvimento do seu navegador e pesquisar na web para obter mais informações. Outra maneira de definir um ponto de interrupção é incluir uma declaração no depurador (que consiste em simplesmente em uma palavra-chave) em seu programa. Se as ferramentas de desenvolvedor do seu navegador estão ativos, o programa fará uma pausa sempre que ele atingir esta declaração e você será capaz de inspecionar o seu estado. 158 | 159 | ## Propagação de erros 160 | 161 | Infelizmente nem todos os problemas podem ser evitados pelo programador. Se o seu programa se comunica com o mundo externo de qualquer forma há uma chance da entrada de outros sistemas estarem inválidos ou a comunicação estar quebrada ou inacessível. 162 | 163 | Programas simples ou programas que são executados somente sob a sua supervisão pode se dar ao luxo de simplesmente desistir quando esse problema ocorre. Você vai olhar para o problema e tentar novamente. Aplicações "reais" por outro lado espera que nunca falhe. Às vezes a maneira correta é tirar a má entrada rapidamente para que o programe continue funcionando. Em outros casos é melhor informar ao usuário o que deu de errado para depois desistir. Mas em qualquer situação o programa tem de fazer algo rapidamente em resposta ao problema. 164 | 165 | Digamos que você tenha uma função `promptInteger` que pede para o usuário um número inteiro e retorna-o. O que ele deve retornar se a entradas do usuário for incorreta? 166 | 167 | Uma opção é fazê-lo retornar um valor especial. Escolhas comuns são valores nulos e indefinido. 168 | 169 | ````js 170 | function promptNumber(question) { 171 | var result = Number(prompt(question, "")); 172 | if (isNaN(result)) return null; 173 | else return result; 174 | } 175 | 176 | console.log(promptNumber("How many trees do you see?")); 177 | ```` 178 | 179 | Isto é uma boa estratégia. Agora qualquer código que chamar a função `promptNumber` deve verificar se um número real foi lido, e na falha deve de alguma forma recuperar preenchendo um valor padrão ou retornando um valor especial para o seu chamador indicando que ele não conseguiu fazer o que foi solicitado. 180 | 181 | Em muitas situações, principalmente quando os erros são comuns e o chamador deve explicitamente tê-las em conta, retornaremos um valor especial, é uma forma perfeita para indicar um erro. Mas essa maneira no entanto tem suas desvantagens. Em primeiro lugar, como a função pode retornar todos os tipos possíveis de valores? Para tal função é difícil encontrar um valor especial que pode ser distinguido a partir de um resultado válido. 182 | 183 | O segundo problema é com o retorno de valores especiais, isso pode levar a um código muito confuso. Se um pedaço de código chama a função `promptNumber` 10 vezes, teremos que verificar 10 vezes se nulo foi devolvido. E se a sua resposta ao encontrar nulo é simplesmente retornar nulo, o chamador por sua vez tem que verificar assim por diante. 184 | 185 | ## Exceções 186 | 187 | Quando uma função não pode prosseguir normalmente, o que gostaríamos de fazermos é simplesmente parar o que esta sendo feito e saltar imediatamente de volta para o lugar onde devemos lidar com o problema. Isto é o que faz o tratamento de exceção. 188 | 189 | As exceções são um mecanismo que torna possível parar o código que é executado com problema disparando (ou lançar) uma exceção que nada mais é que um simples valor. Levantando uma exceção lembra um pouco um retorno super carregado a partir de uma função: ele salta para fora não apenas da função atual mas também fora de todo o caminho de seus interlocutores para a primeira chamada que iniciou a execução atual. Isto é chamado de desenrolamento do `stack`. Você pode se lembrar das chamadas de função do `stack` que foi mencionado no Capítulo 3. Uma exceção é exibida no `stack` indicando todos os contextos de chamadas que ele encontrou. 190 | 191 | Se as exceções tivessem um `stack` de uma forma ampliada não seria muito útil. Eles apenas fornecem uma nova maneira de explodir o seu programa. Seu poder reside no fato de que você pode definir "obstáculos" ao longo do seu `stack` para capturar a exceção. Depois você pode fazer alguma coisa com ele no ponto em que a exceção foi pega para que o programa continua em execução. 192 | 193 | Aqui está um exemplo: 194 | 195 | ````js 196 | function promptDirection(question) { 197 | var result = prompt(question, ""); 198 | if (result.toLowerCase() == "left") return "L"; 199 | if (result.toLowerCase() == "right") return "R"; 200 | throw new Error("Invalid direction: " + result); 201 | } 202 | 203 | function look() { 204 | if (promptDirection("Which way?") == "L") 205 | return "a house"; 206 | else 207 | return "two angry bears"; 208 | } 209 | 210 | try { 211 | console.log("You see", look()); 212 | } catch (error) { 213 | console.log("Something went wrong: " + error); 214 | } 215 | ```` 216 | 217 | A palavra-chave `throw` é usada para gerar uma exceção. Para tratar uma exceção basta envolver um pedaço de código em um bloco `try`, seguido pela palavra-chave `catch`. Quando o código no bloco `try` causa uma exceção a ser lançada o bloco `catch` é chamado. O nome da variável (entre parênteses) após captura será vinculado ao valor de exceção. Após o término do bloco `catch` ou do bloco `try` o controle prossegue sob toda a instrução `try/catch`. 218 | 219 | Neste caso usaremos o construtor de erro para lançar o nosso valor de exceção. Este é um construtor JavaScript normal que cria um objeto com uma propriedade de mensagem. Em ambientes de JavaScript modernos instâncias deste construtor também coletam informações para o `stack` e sobre chamadas que existia quando a exceção foi criado, o chamado `stack` de rastreamento. Esta informação é armazenada na propriedade do `stack` e pode ser útil ao tentar depurar um problema: ela nos diz a função precisa de onde ocorreu o problema e que outras funções que levou até a chamada onde ocorreu a falha. 220 | 221 | Note que se olharmos para função `promptDirection` podemos ignoramos completamente a possibilidade de que ela pode conter erros. Esta é a grande vantagem do tratamento de erros - manipulação de erro no código é necessário apenas no ponto em que o erro ocorre e no ponto onde ele é tratado. Essas funções no meio pode perder tudo sobre ela. 222 | 223 | Bem, estamos quase lá. 224 | 225 | ## Limpeza após exceções 226 | 227 | Considere a seguinte situação: a função `withContext` quer ter certeza de que durante a sua execução, o contexto de nível superior da variável tem um valor de contexto específico. Depois que terminar ele restaura esta variável para o seu valor antigo. 228 | 229 | ````js 230 | var context = null; 231 | 232 | function withContext(newContext, body) { 233 | var oldContext = context; 234 | context = newContext; 235 | var result = body(); 236 | context = oldContext; 237 | return result; 238 | } 239 | ```` 240 | 241 | Como que o `body` gera uma exceção? Nesse caso, a chamada para `withContext` será exibido no `stack` pela exceção, e o contexto nunca será definido de volta para o seu valor antigo. 242 | 243 | O `try` tem mais uma declaração. Eles podem ser seguidos por um `finally` com ou sem o bloco `catch`. 244 | O bloco `finally` significa "não importa o que aconteça execute este código depois de tentar executar o código do bloco try". 245 | Se uma função tem de limpar alguma coisa, o código de limpeza geralmente deve ser colocado em um bloco `finally`. 246 | 247 | ````js 248 | function withContext(newContext, body) { 249 | var oldContext = context; 250 | context = newContext; 251 | try { 252 | return body(); 253 | } finally { 254 | context = oldContext; 255 | } 256 | } 257 | ```` 258 | 259 | Note-se que não temos mais o resultado do `context` para armazenar (o que queremos voltar) em uma variável. Mesmo se sair diretamente do bloco try o último bloco será executado. Então podemos fazer isso de um jeito mais seguro: 260 | 261 | ````js 262 | try { 263 | withContext(5, function() { 264 | if (context < 10) 265 | throw new Error("Not enough context!"); 266 | }); 267 | } catch (e) { 268 | console.log("Ignoring: " + e); 269 | } 270 | // → Ignoring: Error: Not enough context! 271 | 272 | console.log(context); 273 | // → null 274 | ```` 275 | 276 | Mesmo que a chamada da função `withContext` explodiu, `withContext` limpou corretamente a variável `context`. 277 | 278 | ## Captura seletiva 279 | 280 | Quando uma exceção percorre todo o caminho até o final do `stack` sem ser pego, ele é tratado pelo `environment`. Significa que isto é diferente entre os ambientes. Nos navegadores uma descrição do erro normalmente é escrita no console do JavaScript (alcançável através de "Ferramentas" do navegador no menu de "developer"). 281 | 282 | Erros passam muitas vezes como algo normal, isto acontece para erros do programador ou problemas que o browser não consegue manipular o erro. Uma exceção sem tratamento é uma forma razoável para indicar a um programa que ele esta quebrado e o console JavaScript em navegadores modernos terá que fornecer-lhe algumas informações no `stack` sobre quais foram as chamadas de funções quando o problema ocorreu. 283 | 284 | Para problemas que se espera que aconteça durante o uso rotineiro chegando como uma exceção e que não seja tratada isso pode não ser uma resposta muito simpática. 285 | 286 | Usos incorretos da linguagem como, a referência a uma variável inexistente, propriedade que tem null ou chamar algo que não é uma função também irá resultar em lançamentos de exceções. Essas exceções podem ser capturados como outra qualquer. 287 | 288 | Quando um pedaço de código é inserido no bloco `catch`, todos nós sabemos que algo em nosso corpo `try` pode ou vai causar uma exceção. Mas nós não sabemos o que ou qual exceção que sera lançada. 289 | 290 | O JavaScript (tem uma omissão gritante) não fornece suporte direto para a captura seletiva exceções: ou você manipula todos ou você trata de algum em específico. Isto torna muito fácil supor que a exceção que você recebe é o que você estava pensando quando escreveu o bloco `catch`. 291 | 292 | Mas talvez não seja nenhuma das opções citadas. Alguma outra hipótese pode ser violada ou você pode ter introduzido um erro em algum lugar que está causando uma exceção. Aqui está um exemplo que tentei manter a chamada a função `promptDirection` até que ele receba uma resposta válida: 293 | 294 | ````js 295 | for (;;) { 296 | try { 297 | var dir = promtDirection("Where?"); // ← typo! 298 | console.log("You chose ", dir); 299 | break; 300 | } catch (e) { 301 | console.log("Not a valid direction. Try again."); 302 | } 303 | } 304 | ```` 305 | 306 | O `for (;;)` é a construção de um loop infinito de forma intencionalmente que não para sozinho. Nós quebramos o circuito de fora somente quando uma direção válida é fornecida. Mas a mal escrita do `promptDirection` resultará em um erro de "variável indefinida". O bloco `catch` ignora completamente o seu valor de exceção, supondo que ele sabe qual é o problema ele trata equivocadamente o erro de variável como uma indicação de má entrada. Isso não só causa um loop infinito mas também exibi uma mensagem de erro incorretamente sobre a variável que estamos usando. 307 | 308 | Como regra geral não capturamos exceções a menos que tenha a finalidade de monitora-las em algum lugar, por exemplo através de softwares externos conectados à nossa aplicação que indica quando nossa aplicação está caída. E assim mesmo podemos pensar cuidadosamente sobre como você pode estar escondendo alguma informação. 309 | 310 | E se quisermos pegar um tipo específico de exceção? Podemos fazer isso através da verificação no bloco catch para saber se a exceção que temos é a que queremos, dai então é so lançar a exceção novamente. Mas como que nós reconhecemos uma exceção? 311 | 312 | Naturalmente nós poderíamos fazer uma comparação de mensagens de erros. Mas isso é uma forma instável de escrever código pois estaríamos utilizando informações que são destinadas ao consumo humano (a mensagem) para tomar uma decisão programática. Assim que alguém muda (ou traduz) a mensagem o código irá parar de funcionar. 313 | 314 | Em vez disso, vamos definir um novo tipo de erro e usar `instanceof` para identificá-lo. 315 | 316 | ````js 317 | function InputError(message) { 318 | this.message = message; 319 | this.stack = (new Error()).stack; 320 | } 321 | 322 | InputError.prototype = Object.create(Error.prototype); 323 | InputError.prototype.name = "InputError"; 324 | ```` 325 | 326 | O `prototype` é feito para derivar-se de `Error.prototype` para que `instanceof Error` retorne `true` para objetos de `InputError`. Nome a propriedade também é dada para tipos de erro padrão (`Error`, `SyntaxError`, `ReferenceError` e assim por diante) para que também se tenha uma propriedade. 327 | 328 | A atribuição da propriedade no `stack` tenta deixar o rastreamento do objeto pelo `stacktrace` um pouco mais útil, em plataformas que suportam a criação de um objeto de erro regular pode usar a propriedade de `stack` do objeto para si próprio. 329 | 330 | Agora `promptDirection` pode lançar um erro. 331 | 332 | ````js 333 | function promptDirection(question) { 334 | var result = prompt(question, ""); 335 | if (result.toLowerCase() == "left") return "L"; 336 | if (result.toLowerCase() == "right") return "R"; 337 | throw new InputError("Invalid direction: " + result); 338 | } 339 | ```` 340 | 341 | E o loop pode ser tratado com mais cuidado. 342 | 343 | ````js 344 | for (;;) { 345 | try { 346 | var dir = promptDirection("Where?"); 347 | console.log("You chose ", dir); 348 | break; 349 | } catch (e) { 350 | if (e instanceof InputError) 351 | console.log("Not a valid direction. Try again."); 352 | else 353 | throw e; 354 | } 355 | } 356 | ```` 357 | 358 | Isso vai pegar apenas os casos de `InputError` e através disso deixa algumas exceções independentes. Se você introduzir um erro de digitação ou um erro de variável indefinida a aplicação nos avisará. 359 | 360 | ## Asserções 361 | 362 | As asserções são ferramentas que auxiliam na verificação da sanidade básica de erros do programador. Considere essa função auxiliar que afirma: 363 | 364 | ````js 365 | function AssertionFailed(message) { 366 | this.message = message; 367 | } 368 | AssertionFailed.prototype = Object.create(Error.prototype); 369 | 370 | function assert(test, message) { 371 | if (!test) 372 | throw new AssertionFailed(message); 373 | } 374 | 375 | function lastElement(array) { 376 | assert(array.length > 0, "empty array in lastElement"); 377 | return array[array.length - 1]; 378 | } 379 | ```` 380 | 381 | Isso fornece uma maneira compacta de fazer cumprir as expectativas solicitadas para quebrar um programa se a condição descrita não for válida. Por exemplo se a função `lastElement` que busca o último elemento de uma matriz voltar indefinida para matrizes vazias caso a declaração for omitida. Buscar o último elemento de uma matriz vazia não faz muito sentido por isso é quase certeza de que um erro de programação pode acontecer. 382 | 383 | As afirmações são maneiras de certificar-se de que erros pode causar falhas e qual o ponto deste erro ao invés de valores sem sentido produzidos silenciosamente que pode acarretar problemas em uma parte do programa a qual não se tem nenhuma relação de onde ocorreu realmente. 384 | 385 | ## Resumo 386 | 387 | Erros e má entrada acontecem. Erros de programas precisam ser encontrados e corrigidos. Eles podem tornar-se mais fácil de perceber quando se tem uma suites de testes automatizadas e asserções adicionadas em seu programa. 388 | 389 | Problemas causados por fatores fora do controle do programa devem geralmente serem tratados normalmente. Às vezes quando o problema pode ser tratado localmente, valores de retorno especiais é um caminho sensato para monitorá-los. Caso contrário as exceções são preferíveis. 390 | 391 | Lançar uma exceção faz com que `stack` de chamadas se desencadeie o bloco `try/catch` até a parte inferior do `stack`. O valor da exceção será capturado pelo bloco `catch` onde podemos verificar se ele é realmente do tipo de exceção esperada e em seguida fazer algo com ela. Para lidar com o fluxo de controle imprevisível causado pelas exceções, o bloco `finally` pode ser utilizado para garantir que um pedaço de código seja sempre executado. 392 | 393 | ## Exercícios 394 | 395 | ### Tente outra vez... 396 | 397 | Digamos que você tenha uma função `primitiveMultiply` que em 50 por cento dos casos multiplica dois números e em outros 50 por cento levanta uma exceção do tipo `MultiplicatorUnitFailure`. Escreva uma função que envolva esta função `MultiplicatorUnitFailure` e simplesmente tente até que uma chamada seja bem-sucedido retornando o resultado. 398 | 399 | Certifique-se de lidar com apenas as exceções que você está tentando manipular. 400 | 401 | ````js 402 | function MultiplicatorUnitFailure() {} 403 | 404 | function primitiveMultiply(a, b) { 405 | if (Math.random() < 0.5) 406 | return a * b; 407 | else 408 | throw new MultiplicatorUnitFailure(); 409 | } 410 | 411 | function reliableMultiply(a, b) { 412 | // Coloque seu código aqui. 413 | } 414 | 415 | console.log(reliableMultiply(8, 8)); 416 | // → 64 417 | ```` 418 | 419 | **Dica** 420 | 421 | A chamada de `primitiveMultiply` obviamente deve acontecer em um bloco `try`. 422 | O bloco `catch` fica responsável para relançar a exceção quando não é uma instância de `MultiplicatorUnitFailure` e garantir que a chamada é repetida quando ele é uma instância de `MultiplicatorUnitFailure`. 423 | 424 | Para refazer o processo, você pode usar um `loop` que quebra somente quando a chamada for bem sucedida; veja os exemplos de recursão nos capítulos anteriores e faça o uso; espero que você não tenha uma grande séries de erros na função `primitiveMultiply` pois isso pode extrapolar o `stack` e entrar em loop infinito. 425 | 426 | ### A caixa trancada 427 | 428 | Considere o seguinte objeto: 429 | 430 | ````js 431 | var box = { 432 | locked: true, 433 | unlock: function() { this.locked = false; }, 434 | 435 | lock: function() { this.locked = true; }, 436 | 437 | _content: [], 438 | 439 | get content() { 440 | if (this.locked) throw new Error("Locked!"); 441 | return this._content; 442 | } 443 | }; 444 | ```` 445 | 446 | Isto é uma caixa com um cadeado. Dentro dela tem um `array` mas você pode obtê-lo apenas quando a caixa for desbloqueada. Não é permitido acessar a propriedade `_content` diretamente. 447 | 448 | Escreva uma função chamada `withBoxUnlocked` que assume o valor da função que é passada por argumento para abrir esta caixa. Execute a função e em seguida garanta que a caixa está bloqueada antes de voltar novamente; não importa se o argumento da função retornou normalmente ou emitiu uma exceção. 449 | 450 | ````js 451 | function withBoxUnlocked(body) { 452 | // Your code here. 453 | } 454 | 455 | withBoxUnlocked(function() { 456 | box.content.push("gold piece"); 457 | }); 458 | 459 | try { 460 | withBoxUnlocked(function() { 461 | throw new Error("Pirates on the horizon! Abort!"); 462 | }); 463 | } catch (e) { 464 | console.log("Error raised:", e); 465 | } 466 | 467 | console.log(box.locked); 468 | // → true 469 | ```` 470 | 471 | Para ganhar pontos extras, certifique-se de que chamou `withBoxUnlocked` quando a caixa já estava desbloqueada, pois a caixa deve sempre permanecer desbloqueada. 472 | 473 | **Dica:** 474 | 475 | Você provavelmente deve ter adivinhado que este exercício solicita o uso do bloco `finally`. 476 | Sua função deve ser destravar a caixa e em seguida chamar a função que vem de argumento dentro da função `withBoxUnlocked`. 477 | E no `finally` ele deve travar a caixa novamente. 478 | 479 | Para certificar-se de que nós não bloqueamos a caixa quando ela já estava bloqueada verifique no início da função se a mesma verificação é válida para quando a caixa esta desbloqueada e para quando quisermos bloquear ela novamente. 480 | -------------------------------------------------------------------------------- /chapters/10-modulos.md: -------------------------------------------------------------------------------- 1 | 2 | Capítulo 10 3 | 4 | # Módulos 5 | 6 | > Um programador iniciante escreve seus programas como uma formiga constrói seu formigueiro, um pedaço de cada vez, sem pensar na estrutura maior. Seus programas irão parecer como areia solta. Eles podem durar um tempo, mas se crescem demais, desmoronam. 7 | > 8 | > Percebendo esse problema, o programador começará a gastar muito tempo pensando sobre a estrutura. Seus programas serão rigidamente estruturados, como esculturas em pedra. Eles são sólidos, mas quando precisam mudar, devem ser quebrados. 9 | 10 | > O programador experiente sabe quando aplicar uma estrutura e quando deixar as coisas mais simples. Seus programas são como argila, sólidos mas ainda maleáveis. 11 | 12 | > —Master Yuan-Ma, The Book of Programming 13 | 14 | Todo programa possui uma forma. Em menor escala essa forma é determinada pela divisão em funções e os blocos dentro destas funções. Programadores têm muita liberdade na forma que dão aos seus programas. É determinado mais pelo bom (ou mau) gosto, do que pela funcionalidade planejada. 15 | 16 | Quando olhamos um programa grande em seu todo, funções individuais começam a se misturar e seria bom possuir uma unidade maior de organização. 17 | 18 | Módulos dividem programas em blocos de código, que por algum critério pertencem a uma mesma unidade. Este capítulo explora alguns dos benefícios que estes agrupamentos fornecem e mostra algumas técnicas para construção de módulos em JavaScript. 19 | 20 | ## Organização 21 | 22 | Existem algumas razões porque autores dividem seus livros em capítulos e seções. Elas facilitam para o leitor entender como o livro foi feito ou achar uma parte específica em que está interessado. Elas também ajudam o autor, dando um foco claro para cada seção. 23 | 24 | Os benefícios de dividir um programa em vários arquivos ou módulos são semelhantes, ajudam as pessoas que não estão familiarizadas com o código a achar o que elas buscam, e ajudam o programador a colocar coisas semelhantes juntas. 25 | 26 | Alguns programas são organizados seguindo o modelo de um texto tradicional, com uma ordem bem definida que encoraja o leitor a percorrer o programa, e muito falatório (comentários) fornecendo uma descrição coerente do código. Isso faz o programa muito menos intimidador (ler código desconhecido é geralmente intimidador). Mas existe um lado ruim que é a maior quantidade de trabalho a fazer e dificulta um pouco as alterações, porque os comentários tendem a ser mais interligados do que o código em si. 27 | 28 | Como regra geral, organização tem um custo, e é nos estágios iniciais do projeto, quando não sabemos com certeza aonde vamos e que tipo de módulos o programa precisará. Eu defendo uma estrutura minimalista, com pouca estrutura. Apenas coloque tudo em um simples arquivo até que o código esteja estabilizado. Dessa maneira, você não estará se sobrecarregando pensando em organização enquanto tem pouca informação, não perderá tempo fazendo e desfazendo coisas, e não irá acidentalmente travar-se em uma estrutura que não serve realmente para seu programa. 29 | 30 | ## Namespaces 31 | 32 | A maioria das linguagens modernas de programação têm um nível de escopo entre "global" (todos podem ver) e "local" (só esta função pode ver isto). JavaScript não. Assim, por padrão, tudo o que precisa ser visível fora do pequeno escopo da função atual é visível em todos os lugares. 33 | 34 | Poluição de Namespace, o problema de um monte de código não relacionado ter que compartilhar um único conjunto de nomes de variáveis globais, foi mencionado no capítulo 4, onde o objeto `Math` foi dado como um exemplo de um objeto que age como uma espécie de módulo por um agrupamento série de funcionalidades relacionadas com a matemática. 35 | 36 | Embora JavaScript não possua a criação de módulos nativamente, objetos podem ser usados para criar sub-namespaces publicamente acessíveis, e funções podem ser usadas para criar um namespace privado dentro de um módulo. Vou demonstrar algumas técnicas que nos permitirão construir módulos namespace isolados bem convenientes. 37 | 38 | ## Reuso 39 | 40 | Em um projeto "flat" (plano), não é claro quais partes do código são necessárias para se usar uma função em particular. Se, no meu programa para espionar inimigos (*spying on enemies*), eu escrever uma função para ler os arquivos de configuração, e agora eu uso essa função novamente em outro projeto, eu devo ir e copiar as partes do programa antigo que são relevantes para a funcionalidade que eu preciso, e colá-las no meu novo programa. Então, se eu encontrar um erro nesse código, eu vou consertar isso neste programa que eu estava trabalhando no momento, e esquecer de também consertar no outro programa. 41 | 42 | Uma vez que você tenha muitos pedaços de código compartilhados e duplicados, você vai se encontrar perdendo uma grande quantidade de tempo e energia organizá-los e mantê-los atualizados. 43 | 44 | Quando partes de funcionalidades que são independentes são colocadas em arquivos e módulos separados, elas podem ser rastreadas mais facilmente, atualizadas quando uma nova versão for criada, ou até mesmo compartilhadas, tendo várias partes do código que desejam usá-las carregando o mesmo arquivo. 45 | 46 | Essa idea fica ainda mais poderosa quando as relações entre os módulos - onde outros módulos cada módulo depende - são explicitamente especificados. Você pode então automatizar o processo de instalação e atualização de módulos externos. 47 | 48 | E, levando isso ainda mais longe, imagine um serviço online que rastreia e distribui centenas de milhares destes módulos, permitindo a você buscar pela funcionalidade que deseja, e, uma vez que você a encontre, configure-a no seu projeto para ser baixada automaticamente. 49 | 50 | Este serviço existe. É chamado NPM (npmjs.org). NPM consiste em um banco de dados online de módulos, e uma ferramenta para download e atualização dos módulos que seu programa depende. Ele cresceu com o Node.js. o ambiente JavaScript *browser-less* (que não depende do navegador), discutido no capítulo 20, mas também pode ser usado quando programando para o navegador. 51 | 52 | ## Desacoplamento 53 | 54 | Outro importante papel dos módulos é os de isolar partes de código um do outro, da mesma forma que as interfaces dos objetos no capítulo 6 fazem. Um módulo bem desenvolvido fornece uma interface para uso de códigos externos, e mesmo que o módulo continue sendo trabalhado (bugs consertados, funcionalidades adicionadas) a interface existente permanece estável, assim outro módulos podem usar uma nova e melhorada versão sem qualquer alteração neles mesmos. 55 | 56 | Note que uma interface estável não significa que novos elementos não são adicionados. Isso apenas significa que elementos existentes não serão removidos ou seus significados não serão alterados. 57 | 58 | Construir a interface de um módulo que permite que este cresça sem quebras na antiga interface significa encontrar um balanço entre expor a menor quantidade de conceitos internos ao mundo exterior quanto possível, e ainda assim criar uma "linguagem" exposta pela interface que seja poderosa e flexível o suficiente para ser aplicada em uma vasta variedade de situações. 59 | 60 | Para interfaces que expões um único e focado conceito, como um arquivo leitor de configuração, isso é natural. Para as outras interfaces, como um componente editor de texto, onde código externo precisa acessar vários conceitos diferentes, isso requer cuidado no projeto. 61 | 62 | ## Funções como namespaces 63 | 64 | Funções são o único construtor em JavaScript que criam um novo escopo. Então se nós desejamos que nossos módulos tenham um escopo próprio, teremos que colocá-los em funções de alguma forma. 65 | 66 | Considere este módulo trivial que associa nomes com o número dos dias da semana retornado pelo método `getDay` de um objeto *date*. 67 | 68 | ```javascript 69 | var names = ["Sunday", "Monday", "Tuesday", "Wednesday", 70 | "Thursday", "Friday", "Saturday"]; 71 | function dayName(number) { 72 | return names[number]; 73 | } 74 | 75 | console.log(dayName(1)); 76 | // → Monday 77 | ``` 78 | 79 | A função `dayName` é parte desta interface, mas a variável `names` não. Nós preferimos não deixá-la no escopo global. 80 | 81 | Podemos fazer isso: 82 | 83 | ```javascript 84 | var dayName = function() { 85 | var names = ["Sunday", "Monday", "Tuesday", "Wednesday", 86 | "Thursday", "Friday", "Saturday"]; 87 | return function(number) { 88 | return names[number]; 89 | }; 90 | }(); 91 | 92 | console.log(dayName(3)); 93 | // → Wednesday 94 | ``` 95 | 96 | Agora `names` é uma variável local dentro de uma função (anônima). Esta função é criada e chamada imediatamente, e seu valor retornado (a função `dayName`) é armazenada em uma variável. Podemos ter páginas e mais páginas de código nessa função, criando centenas de variáveis locais. Elas serão todas internas ao módulo, visíveis ao próprio módulo, mas não visível a códigos externos. 97 | 98 | Um padrão similar é usado para isolar inteiramente código do mundo exterior. O módulo abaixo tem algum efeito, mas não fornece qualquer valor para outros módulos usarem. 99 | 100 | ```javascript 101 | (function() { 102 | function square(x) { return x * x; } 103 | var hundred = 100; 104 | 105 | console.log(square(hundred)); 106 | })(); 107 | // → 10000 108 | ``` 109 | 110 | Este código simplesmente imprime o quadrado de cem (no mundo real, este poderia ser um módulo que adiciona um método a algum prototype, ou configura algum *widget* em uma página da web). Ele encapsula seu código em uma função para, novamente, prevenir que as variáveis que ele usa internamente estejam no escopo global. 111 | 112 | Por que a função namespace está encapsulada em uma par de parênteses? Isso tem relação com um truque da sintaxe JavaScript. Se uma expressão começa com a palavra-chave `function`, ela é uma expressão de função. Entretanto, se uma declaração inicia com esta palavra-chave, será uma declaração de função, que requer um nome e não pode ser chamada imediatamente. Mesmo que uma declaração comece com uma expressão, a segunda regra tem precedência, e se os parênteses extras foram esquecidos no exemplo acima, isso irá produzir um erro de sintaxe. Você pode imaginá-los como um truco para forçar a linguagem a entender que nós queremos escrever uma expressão. 113 | 114 | ## Objetos como namespaces 115 | 116 | Agora imagine que o módulo dia-da-semana (*day-of-the-week*) precise fornecer não uma, mas duas funções, porque nós adicionamos uma função `dayNumber` que vai de um nome para um número. Nós podemos mais simplesmente retornar a função, mas devemos encapsular as duas funções em um objeto. 117 | 118 | ```javascript 119 | var weekDay = function() { 120 | var names = ["Sunday", "Monday", "Tuesday", "Wednesday", 121 | "Thursday", "Friday", "Saturday"]; 122 | return { 123 | name: function(number) { return names[number]; }, 124 | number: function(name) { return names.indexOf(name); } 125 | }; 126 | }(); 127 | 128 | console.log(weekDay.name(weekDay.number("Sunday"))); 129 | // → Sunday 130 | ``` 131 | 132 | Para módulos maiores, juntar todos os módulos exportados em um objeto no fim da função se torna algo incômodo, e geralmente requer que façamos algo repetido. Isso pode ser melhorado declarando um objeto, usualmente nomeado `exports`, e adicionando propriedades a este objeto sempre que nós definirmos algo que precise ser exportado. Este objeto pode então ser retornado, ou aceito como um parâmetro armazenado em algum lugar pelo código exterior ao módulo. 133 | 134 | ```javascript 135 | (function(exports) { 136 | var names = ["Sunday", "Monday", "Tuesday", "Wednesday", 137 | "Thursday", "Friday", "Saturday"]; 138 | 139 | exports.name = function(number) { 140 | return names[number]; 141 | }; 142 | exports.number = function(name) { 143 | return names.indexOf(name); 144 | }; 145 | })(window.weekDay = {}); 146 | 147 | console.log(weekDay.name(weekDay.number("Saturday"))); 148 | // → Saturday 149 | ``` 150 | 151 | ## Removendo do escopo global 152 | 153 | O padrão acima é usado normalmente em módulos JavaScript criados para o navegador. Eles requerem um simples e conhecido nome global, e encapsular seu código em uma função para ter seu namespace privado próprio. 154 | 155 | Ainda existe um problema quando múltiplos módulos reivindicam o mesmo nome, ou quando você quer, por qualquer motivo, carregar duas versões do mesmo módulo de forma conjunta. 156 | 157 | Com um pequeno encanamento, nós podemos criar um sistema que permite que aos módulos requererem diretamente por interfaces de objetos de outros módulos que eles precisem de acessar, sem precisarmos usar o escopo global. Isso resolve os problemas mencionados acima e tem um benefício adicional de ser explícito sobre suas dependências, tornando difícil usar acidentalmente algum módulo sem declarar que você precisa dele. 158 | 159 | Nosso objetivo é uma função 'require' que, quando dado o nome de um módulo, vai carregar esse arquivo (do disco ou da web, dependendo da plataforma que estivermos rodando), e retornar o valor apropriado da interface. 160 | 161 | Para isso nós precisamos de pelo menos duas coisas. Primeiramente, nós vamos imaginar que temos uma função `readFile` (que não está presente por padrão no JavaScript), que retorna o conteúdo do arquivo com um nome fornecido. Existem formas de acessar a web com JavaScript no navegador, e acessar o disco rígido com outras plataformas JavaScript, mas elas são mais envolvidas. Por agora, nós apenas pretendemos desta simples função. 162 | 163 | Em segundo lugar, nós precisamos de ser capazes, quando tivermos uma string contendo o código (lida do arquivo), de realmente executar o código como um programa JavaScript. 164 | 165 | ## Avaliando dados como código 166 | 167 | Existem várias formas de se pegar dados (uma `string` de código) e rodá-los no contexto do programa atual. 168 | 169 | A mais óbvia maneira é o operador padrão especial `eval`, que vai executar a string de código no escopo atual. Isso usualmente é uma ideia muito ruim, porque quebra algumas propriedades que escopos normalmente tem (ser isolado do mundo externo é a mais notável). 170 | 171 | ```javascript 172 | function evalAndReturnX(code) { 173 | eval(code); 174 | return x; 175 | } 176 | 177 | console.log(evalAndReturnX("var x = 2")); 178 | // → 2 179 | ``` 180 | 181 | A melhor forma de converter dados dentro do programa é usar uma função construtora. Ela recebe como argumentos uma lista de nomes de argumentos separados por vírgula, e então uma string contendo o corpo da função. 182 | 183 | ```javascript 184 | var plusOne = new Function("n", "return n + 1;"); 185 | console.log(plusOne(4)); 186 | // → 5 187 | ``` 188 | 189 | Isso é precisamente o que precisamos - podemos encapsular o código para um módulo em uma função, com este escopo de função se tornando nosso escopo de módulo. 190 | 191 | ## Require 192 | 193 | Se a nova função construtora, usada pelo nosso módulo de carregamento, encapsula o código em uma função de qualquer forma, nós podemos omitir a função *namespace* encapsuladora atual dos arquivos. Nós também vamos fazer `exports` um argumento à função módulo, então o módulo não precisará de declarar isso. Isso remove um monte de barulho supérfluo do nosso módulo de exemplo: 194 | 195 | ```javascript 196 | var names = ["Sunday", "Monday", "Tuesday", "Wednesday", 197 | "Thursday", "Friday", "Saturday"]; 198 | 199 | exports.name = function(number) { 200 | return names[number]; 201 | }; 202 | exports.number = function(name) { 203 | return names.indexOf(name); 204 | }; 205 | ``` 206 | 207 | Essa é uma implementação mínima de `require`: 208 | 209 | ```javascript 210 | function require(name) { 211 | var code = new Function("exports", readFile(name)); 212 | var exports = {}; 213 | code(exports); 214 | return exports; 215 | } 216 | 217 | console.log(require("weekDay").name(1)); 218 | // → Monday 219 | ``` 220 | 221 | Quando usando este sistema, um módulo tipicamente começa com pequenas declarações de variáveis que carregam os módulos que ele precisa. 222 | 223 | ```javascript 224 | var weekDay = require("weekDay"); 225 | var today = require("today"); 226 | 227 | console.log(weekDay.name(today.dayNumber())); 228 | ``` 229 | 230 | A implementação de require acima tem diversos problemas. Primeiro, ela vai carregar e rodar um módulo todas as vezes que este for "require-d" (requisitado), então se diversos módulos têm a mesma dependência, ou uma chamada require é colocada dentro de uma função que vai ser chamada múltiplas vezes, tempo e energia serão desperdiçados. 231 | 232 | Isso pode ser resolvido armazenando os módulos que já tenham sido carregados em um objeto, e simplesmente retornando o valor existente se eles forem carregados novamente. 233 | 234 | O segundo problema é que não é possível para um módulo expor diretamente um valor simples. Por exemplo, um módulo pode querer exportar apenas o construtor do tipo do objeto que ele define. Por agora, isso não pode ser feito, porque `require` sempre vai usar o objeto `exports` que ele cria como o valor exportado. 235 | 236 | A solução tradicional para isso é fornecer outra variável, `module`, que é um objeto que tem a propriedade `exports`. Essa propriedade inicialmente aponta para o objeto vazio criado por require, mas pode ser sobrescrita com outro valor para exportar algo a mais. 237 | 238 | ```javascript 239 | function require(name) { 240 | if (name in require.cache) 241 | return require.cache[name]; 242 | 243 | var code = new Function("exports, module", readFile(name)); 244 | var exports = {}, module = {exports: exports}; 245 | code(exports, module); 246 | 247 | require.cache[name] = module.exports; 248 | return module.exports; 249 | } 250 | require.cache = Object.create(null); 251 | ``` 252 | 253 | Agora temos um sistema de módulo que usa uma simples variável global (`require`) para permitir que módulos encontrem e usem um ao outro sem ter que ir para o escopo global. 254 | 255 | Este estilo de sistema de módulos é chamado "Módulos CommonJS", após o pseudo-padrão que o implementou pela primeira vez. Ele também é feito dentro do Node.js. Implementações reais fazem bem mais do que o exemplo que eu mostrei. Mais importante, eles tem uma forma muito mais inteligente de ir de um nome de módulo para uma parte de código real, permitindo ambos caminhos relativos e nomes de módulos registrados "globalmente". 256 | 257 | ## Carregando módulos lentamente 258 | 259 | Embora seja possível usar a técnica acima para carregar JavaScript no navegador, isso é um pouco complicado. A razão para isso é que ler um arquivo (módulo) na web é muito mais lento que ler este mesmo arquivo do seu disco rígido. JavaScript no navegador é obrigado a se comportar de tal forma que, enquanto um script esteja rodando, nada mais pode acontecer no site que ele está rodando. Isso significa que se todas as chamadas `require` carregarem algo em algum servidor web distante, a página vai ficar congelada por um doloroso longo período durante sua inicialização. 260 | 261 | Existem maneiras de se trabalhar isso, por exemplo, rodando outro programa (como o Browserify) em seu programa antes, que irá concatenar todas as dependências olhando todas as chamadas `require`, e colocando-as em juntas em um grande arquivo. 262 | 263 | Outra solução é encapsular seu módulo em uma função, carregar os módulos que ela depende em segundo plano, e apenas rodas essa função quando todas suas dependências forem carregadas. Isso é o que o sistema de módulos AMD ("Asynchronous Module Definition") faz. 264 | 265 | Nosso programa trivial com dependências, em AMD, se parece com isso: 266 | 267 | ```javascript 268 | define(["weekDay", "today"], function(weekDay, today) { 269 | console.log(weekDay.name(today.dayNumber())); 270 | }); 271 | ``` 272 | 273 | A função `define` é o conceito central nessa abordagem. Ela primeiro recebe um array com nomes de módulos, e então uma função que recebe um argumento para cada dependência. Ela vai carregar as dependências (se elas ainda não tiverem sido carregadas) em segundo plano, permitindo que a página continue a trabalhar em quanto está esperando. Uma vez que todas as dependências estejam carregadas, ela vai carregar a função que foi passada, com as interfaces das dependências como argumentos. 274 | 275 | Os módulos que são carregados dessa forma devem conter uma chamada a `define`. O valor usado para sua interface é qualquer valor retornado pela função que é o segundo argumento passado nessa chamada. Aqui está o módulo `weekDay` de novo. 276 | 277 | ```javascript 278 | define([], function() { 279 | var names = ["Sunday", "Monday", "Tuesday", "Wednesday", 280 | "Thursday", "Friday", "Saturday"]; 281 | return { 282 | name: function(number) { return names[number]; }, 283 | number: function(name) { return names.indexOf(name); } 284 | }; 285 | }); 286 | ``` 287 | 288 | Para mostrar uma simples implementação de `define`, vamos supor que também temos uma função `backgroundReadFile`, que pega o nome do arquivo e uma função, e vai chamar a função com o conteúdo do arquivo assim que este for carregado. 289 | 290 | ```javascript 291 | function define(depNames, moduleFunction) { 292 | var deps = [], myMod = define.currentModule; 293 | 294 | depNames.forEach(function(name) { 295 | if (name in define.cache) { 296 | var depMod = define.cache[name]; 297 | } else { 298 | var depMod = {exports: null, 299 | loaded: false, 300 | onLoad: []}; 301 | define.cache[name] = depMod; 302 | backgroundReadFile(name, function(code) { 303 | define.currentModule = depMod; 304 | new Function("", code)(); 305 | }); 306 | } 307 | deps.push(depMod); 308 | if (!depMod.loaded) 309 | depMod.onLoad.push(runIfDepsLoaded); 310 | }); 311 | 312 | function runIfDepsLoaded() { 313 | if (!deps.every(function(m) { return m.loaded; })) 314 | return; 315 | 316 | var args = deps.map(function(m) { return m.exports; }); 317 | var exports = moduleFunction.apply(null, args); 318 | if (myMod) { 319 | myMod.exports = exports; 320 | myMod.loaded = true; 321 | myMod.onLoad.every(function(f) { f(); }); 322 | } 323 | } 324 | runIfDepsLoaded(); 325 | } 326 | define.cache = Object.create(null); 327 | ``` 328 | 329 | Isso é muito mais difícil de seguir que a função `require`. Sua execução não segue um caminho simples e previsível. Ao invés disso, múltiplas operações são definidas para acontecerem em algum tempo não especificado no futuro (quando o módulo for carregado), que obscurece a forma que o código é executado. 330 | 331 | O maior problema que este código lida é coletar os valores das interfaces das dependências do módulo. Para rastrear os módulos, e seus estados, um objeto é criado para cada módulo que é carregado por `define`. Este objeto armazena o valor exportado pelo módulo, um booleano indicando se o módulo já foi completamente carregado e um array de funções para ser chamado quando o módulo tiver sido carregado. 332 | 333 | Um *cache* é usado para prevenir o carregamento de módulos múltiplas vezes, assim como fizemos para o `require`. Quando `define` é chamada, nós primeiro construímos um array de módulos de objetos que representam as dependências deste módulo. Se o nome da dependência corresponde com o nome de um módulo *cacheado*, nós usamos o objeto existente. Caso contrário, nós criamos um novo objeto (com o valor de `loaded` igual a `false`) e armazenamos isso em cache. Nós também começamos a carregar o módulo, usando a função `backgroundReadFile`. Uma vez que o arquivo tenha sido carregado, seu conteúdo é rodado usando o construtor `Function`. 334 | 335 | É assumido que este arquivo também contenha uma (única) chamada a `define`. A propriedade `define.currentModule` é usada para informar a esta chamada sobre o módulo objeto que está sendo carregado atualmente, dessa forma podemos atualizá-lo umas vez e terminar o carregamento. 336 | 337 | Isso é manipulado na função `runIfDepsLoaded`, que é chamada uma vez imediatamente (no caso de não ser necessário carregar nenhuma dependência) e uma vez para cada dependência que termina seu carregamento. Quando todas as dependências estão lá, nós chamamos `moduleFunction`, passando para ela os valores exportados apropriados. Se existe um módulo objeto, o valor retornado da função é armazenado, o objeto é marcado como carregado (*loaded*), e as funções em seu array `onLoad` são chamadas. Isso vai notificar qualquer módulo que esteja esperando que suas dependências sejam carregadas completamente. 338 | 339 | Uma implementação real do AMD é, novamente, bem mais inteligente em relação a resolução dos nomes e suas URLs, e genericamente mais robusta. O projeto RequireJS (http://requirejs.org) fornece uma implementação popular deste estilo que carregamento de módulos. 340 | 341 | ## Projeto de interfaces 342 | 343 | Projetar interfaces para módulos e tipos de objeto é um dos aspectos sutis da programação. Qualquer pedaço não trivial de funcionalidade pode ser modelada de formas diferentes. Encontrar um caminho que funciona bem requer perspicácia e previdência. 344 | 345 | A melhor forma de aprender o valor de um bom projeto de interface é usar várias interfaces, algumas boas, algumas horríveis. Experiência vai ensinar a você o que funciona e o que não funciona. Nunca assuma que uma interface dolorosa de se usar é "da forma que ela deve ser". Conserte-a, ou encapsule-a em uma nova interface de forma que funcione melhor para você. 346 | 347 | ### Previsilibidade 348 | 349 | Se programadores podem prever a forma que a interface vai funcionar, eles (ou você) não vão ser desviados frequentemente pela necessidade de checar como trabalhar com esta interface. Portanto, tente seguir convenções (por exemplo, quando se trata da capitalização de nomes). Quando existe outro módulo ou parte do ambiente padrão JavaScript que faz algo similar ao que você está implementando, é uma boa ideia fazer sua interface se assemelhar a interface existente. Dessa forma, as pessoas que conhecem a interface existente vão se sentir em casa. 350 | 351 | Outra área que previsibilidade é importante é no comportamento do seu código. Pode ser tentador "empilhar inteligência" com a justificativa que isso torna a interface fácil de ser utilizada. Por exemplo, aceitando todos os diferentes tipos e combinações de argumentos, e fazendo "a coisa certa" para todos eles, ou fornecendo dezenas de diferentes funções especializadas por "conveniência" que fornecem pequenas alterações do sabor da funcionalidade do seu módulo. Isso pode tornar o código construído em cima da sua interface um pouco menor, mas isso vai também tornar o código muito mais difícil para as pessoas manterem um modelo mental do comportamento do módulo em suas cabeças. 352 | 353 | ### "Componibilidade" 354 | 355 | Em suas interfaces, tente usar as estruturas de dados mais simples que funcionem e crie funções que façam algo simples e claro - sempre que possível, crie funções puras (veja capítulo 3). 356 | 357 | Por exemplo, não é comum para módulos fornecerem suas próprias coleções de objetos similares a arrays, com sua própria interface para contar e extrair elementos. Tais objetos não terão os métodos `map` e `forEach`, e qualquer função existente que espere um array real não será capaz de trabalhar com estas coleções. Este é um exemplo de componibilidade (*composability*) ruim - o módulo não pode ser facilmente composto com outro código. 358 | 359 | Outro exemplo seria um módulo verificação ortográfica de texto, que podemos necessitar se quisermos escrever um editor de texto. O verificador pode ser construído para funcionar diretamente em qualquer tipo complexo de estrutura de dados que o editor usa, e chamar funções internas diretamente no editor para que o usuário possa escolher entre as sugestões de ortografia. Se formos por esse caminho, o módulo não poderá ser usado com outros programas. De outra forma, se nós definirmos a interface do verificador ortográfico para que possamos passar simples strings e retornar a possível localização do erro, juntamente com um array de correções sugeridas, nós teremos uma interface que pode ser composta com outros sistemas, porque strings e arrays estarão sempre disponíveis. 360 | 361 | ### Interfaces em camadas 362 | 363 | Quando projetando uma interface para uma complexa parte de funcionalidade - digo, enviar email - você geralmente se depara com um dilema. Em uma mão, você não quer sobrecarregar o usuário da sua interface com detalhes. Ele não deve estudar sua interface por 20 minutos antes de ser capaz de enviar um email. Na outra mão, você não quer esconder todos os detalhes - quando pessoas precisam fazer coisas complicadas com seu módulo, eles também devem ser capazes. 364 | 365 | Normalmente a solução é oferecer duas interfaces: uma de "baixo nível" detalhada para situações complexas e uma de "alto nível" simples para uso rotineiro. A segunda pode ser construída de forma simples utilizando as ferramentas fornecidas pela primeira camada. No módulo de email, a interface de alto nível pode simplesmente ser uma função que recebe uma mensagem, um endereço de remetente, um endereço de destinatário e envia o email. A interface de baixo nível deve permitir um controle completo sobre os cabeçalhos do email, anexos, envio de email HTML, e por ai vai. 366 | 367 | ## Resumo 368 | 369 | Módulos fornecem estrutura para programas grandes, separando o código em diferentes arquivos e *namespaces*. Dando a estes módulos interfaces bem definidas os tornam fáceis de se utilizar, reusando-os em contextos diferentes, e continuando os usando mesmo quando evoluem. 370 | 371 | Mesmo que a linguagem JavaScript não auxilie muito quando se trata de módulos, as flexíveis funções e objetos que ela fornece fazem que seja possível definir úteis sistemas de módulo. Escopo de função pode ser utilizado como namespace interno para o módulo, e objetos podem ser usados para armazenar blocos de valores exportados. 372 | 373 | Existem duas abordagens populares para tais módulos. Uma é chamada "Módulos CommonJS", e funciona em torno da função `require` que busca um módulo pelo seu nome e retorna sua interface. A outra abordagem é chamada "AMD", e usa a função assíncrona `define` que recebe um array de nome de módulos e uma função, e depois de carregar os módulos, roda a função com suas interfaces e argumentos. 374 | 375 | ## Exercícios 376 | 377 | ### Nomes dos meses 378 | 379 | Escreva um simples módulo similar ao módulo `weekDay`, que pode converter os números dos meses (*zero-based*, assim como o tipo `Date`) para nomes, e nomes para números. Dê a este módulo seu próprio namespace, pois ele vai precisar de um array interno com o nome dos meses, mas use JavaScript puro, sem nenhum sistema de carregamento de módulos. 380 | 381 | ```javascript 382 | // Your code here. 383 | 384 | console.log(month.name(2)); 385 | // → March 386 | console.log(month.number("November")); 387 | // → 10 388 | ``` 389 | 390 | Ele vai seguir o módulo weekDay praticamente por inteiro. Uma função anônima, chamada imediatamente, encapsula a variável que contém o array de nomes, assim como as duas funções que precisam ser exportadas. As funções são colocadas em um objeto. A interface de objeto retornada é armazenada na variável `month`. 391 | 392 | ### Dependências circulares 393 | 394 | Um assunto complicado na gestão de dependências é o de dependências circulares, onde módulo A depende do módulo B, e B também depende do módulo A. Muitos sistemas simplesmente proíbem isso. CommonJS permite uma forma limitada disso, onde isso funciona se os módulos não trocarem seus objetos exportados por padrão com outro valor, e somente começam a acessar a interface um do outro após terem finalizados seus carregamentos. 395 | 396 | Você pode pensar em algo que dê suporte para essa funcionalidade ser implementada? Olhe anteriormente a definição de `require`, e considere o quê você deve fazer para permitir isso. 397 | 398 | O segredo é adicionar o objeto `exports` criado por um módulo para requisitar o cache antes de rodar o módulo de fato. Isso significa que o módulo não teria tido ainda uma chance de sobrescrever `module.exports`, então não sabemos se ele deseja exportar outro valor. Depois de carregar, o objeto cache é sobrescrito com `module.exports`, que pode ser um valor diferente. 399 | 400 | Mas se, no curso de carregar o módulo, um segundo módulo é carregado e solicita o primeiro módulo, seu objeto `exports` padrão, ainda vazio até este ponto, vai estar no cache, e o segundo módulo vai receber uma referência dele. Se ele não tentar fazer nada com o objeto até que o segundo módulo tenha terminado seu carregamento, as coisas vão funcionar. 401 | 402 | ### Um retorno a vida eletrônica 403 | 404 | Esperando que o capítulo 7 ainda esteja um pouco fresco em sua mente, pense novamente no sistema projetado neste capítulo e elabore um separação em módulo para o código. Para refrescar sua memória, essas são as funções e tipos definidos naquele capítulo, em ordem de aparição. 405 | 406 | - Point 407 | - Grid 408 | - directions 409 | - randomElement 410 | - BouncingCritter 411 | - elementFromChar 412 | - World 413 | - charFromElement 414 | - Wall 415 | - View 416 | - directionNames 417 | - WallFollower 418 | - dirPlus 419 | - LifeLikeWorld 420 | - Plant 421 | - PlantEater 422 | - SmartPlantEater 423 | - Tiger 424 | 425 | Não exagere em criar muitos módulos. Um livro que começa um novo capítulo para cada página provavelmente vai te deixar nervoso, por todo espaço perdido com os títulos. De forma similar, ter que abrir dez arquivos para ler um pequeno projeto não é útil. Vise por três ou cinco módulos. 426 | 427 | Você pode escolher ter algumas funções internas ao módulo, e então inacessíveis a outros módulos. 428 | 429 | Não existe uma única solução correta aqui. Organização de módulos é meramente uma questão de gosto. 430 | 431 | Aqui está o que eu fiz. Coloquei parenteses em torno de funções internas. 432 | 433 | - Module "grid" 434 | + Point 435 | + Grid 436 | + directions 437 | - Module "world" 438 | + (randomElement) 439 | + (elementFromChar) 440 | + (charFromElement) 441 | + View 442 | + World 443 | + LifeLikeWorld 444 | + directions [re-exported] 445 | - Module "simple_ecosystem" 446 | + (randomElement) [duplicated] 447 | + (directionNames) 448 | + (dirPlus) 449 | + Wall 450 | + BouncingCritter 451 | + WallFollower 452 | - Module "ecosystem" 453 | + Wall [duplicated] 454 | + Plant 455 | + PlantEater 456 | + SmartPlantEater 457 | + Tiger 458 | 459 | Eu reexportei o array `directions` do módulo `grid` para `world`, então módulos criados com eles (`ecosystems`) não precisam de saber ou se preocupar da existência do módulo `grid`. 460 | 461 | Eu também dupliquei dois valores minúsculos e genéricos (`randomElement` e `Wall`) pois eles são usados como detalhes internos em contextos diferentes, e não pertencem nas interfaces destes módulos. 462 | -------------------------------------------------------------------------------- /chapters/11-pratica-linguagem-de-programacao.md: -------------------------------------------------------------------------------- 1 | # Linguagem de programação 2 | 3 | > "O avaliador que determina qual o significado da expressões em uma linguagem de programação é apenas mais um programa." 4 | > 5 | > `Hal Abelson e Gerald Sussman, Estrutura e Interpretação de Programas de Computador` 6 | 7 | 8 | --- 9 | 10 | 11 | > "Quando um estudante perguntou ao mestre sobre a natureza do ciclo de dados e controle, Yuan-Ma respondeu: 'Pense em um compilador compilando a si mesmo.'" 12 | > 13 | > `Mestre Yuan-Ma, O Livro de Programação` 14 | 15 | Construir sua própria linguagem de programação é surpreendentemente fácil(desde que você não seja ambicioso demais) e bastante esclarecedor. 16 | 17 | A principal coisa que eu quero mostrar neste capítulo é que não há mágica envolvida na construção de sua própria linguagem. Eu sempre senti que algumas invenções humanas eram imensamente inteligentes e complicadas que eu nunca seria capaz de compreendê-las. Mas com um pouco de leitura e ajustes; tais coisas muitas vezes acabam por ser muito simples. 18 | 19 | Iremos construir uma linguagem de programação chamada **Egg**. Vai ser uma pequena e simples linguagem mas poderosa o suficiente para expressar qualquer computação que você possa imaginar. Ela também permite abstração simples baseadas em funções. 20 | 21 | ## Parsing 22 | 23 | A parte imediatamente mais visível de uma linguagem de programação é sua sintaxe ou notação. Um analisador é um programa que lê um pedaço de texto e produz uma estrutura de dados que refletem a estrutura do programa contida nesse texto. Se o texto não faz um programa válido o analisador deve reclamar e apontar o erro. 24 | 25 | Nossa linguagem terá uma sintaxe simples e uniforme. Tudo em **Egg** é uma expressão. Uma expressão pode ser uma variável, um `Number`, uma `String`, ou uma aplicação. As aplicações são usados para chamadas de função, mas também para construções como `if` ou `while`. 26 | 27 | Para manter o analisador simples, `String` em **Egg** não suportam qualquer coisa como escapes e uma sequência simplesmente de caracteres que não são aspas duplas envolvidas em aspas duplas. Um número é uma sequência de dígitos. Os nomes das variáveis podem consistir de qualquer caractere que não seja um espaço em branco e não tem um significado especial na sintaxe. 28 | 29 | As aplicação será escrita da forma como é em JavaScript; colocando parênteses após uma expressão e com uma série de argumentos entre esses parênteses separados por vírgulas. 30 | 31 | ````javascript 32 | do(define(x, 10), 33 | if(>(x, 5)), 34 | print("large"), 35 | print("small")) 36 | ```` 37 | 38 | A uniformidade da línguagem **Egg** significa coisas que são operadores de JavaScript(como >) nesta línguagem será apenas variáveis normais aplicado apenas como outras funções. E uma vez que a sintaxe também não tem o conceito de um bloco precisamos construir um representador fazendo várias coisas em seqüência. 39 | 40 | A estrutura de dados que o analisador irá usar para descrever um programa será composto de objetos de expressões cada um dos quais tem uma propriedade de tipo que indica o tipo de expressão que é; e as outras propriedades para descreverem o seu conteúdo. 41 | 42 | Expressões do tipo **"value"** representam `Strings`, `literais` ou `Numbers`. O valor da propriedade contém o valor da cadeia ou o número que ele representa. Expressões do tipo **"word"** são usados para identificadores(nomes). Esses objetos têm uma propriedade que contém o nome do identificador de uma `String`. Por fim as expressões **"apply"** representam algo que é uma aplicação. Eles têm uma propriedade de operador que se refere à expressão que são aplicavéis e têm uma propriedade de `args` que refere-se a um conjunto de expressões de argumento. 43 | 44 | A parte `>(x, 5)` do programa anterior seria representado assim: 45 | 46 | ````javascript 47 | { 48 | type: "apply", 49 | operator: {type: "word", name: ">"}, 50 | args: [ 51 | {type: "word", name: "x"}, 52 | {type: "value", value: 5} 53 | ] 54 | } 55 | 56 | ```` 57 | 58 | Essa estrutura de dados é chamado de árvore de sintaxe. Se você imaginar os objetos como pontos de ligações entre eles e com linhas entre esses pontos, ele tem uma forma treelike. O fato de que as expressões contem outras expressões que por sua vez pode conter mais expressões é semelhante à maneira como dividir ramos e dividir novamente. 59 | 60 | ![Syntax three](../img/syntax_tree.png) 61 | 62 | Compare isso com o analisador que escrevemos para o formato de arquivo de configuração no capítulo 9 que tinha uma estrutura simples: dividir a entrada em linhas e tratar essas linhas uma de cada vez. Havia apenas algumas formas simples de mostrar que uma linha foi permitida. 63 | 64 | Aqui temos de encontrar uma abordagem diferente. As expressões não são separados em linhas e elas têm uma estrutura recursiva. Expressões aplicadas contêm outras expressões. 65 | 66 | Felizmente, este problema pode ser resolvido com elegância escrevendo uma função analisadora que é recursiva de uma forma que reflete a natureza recursiva da linguagem. 67 | 68 | Nós definimos uma função `parseExpression` que recebe uma string como entrada e retorna um objeto que contém a estrutura de dados para a expressão no início da cadeia, depois é feito a junção com a parte da cadeia da esquerda para analisar esta expressão. Ao analisar essa `subexpressions`(o argumento para um aplicativo, por exemplo) esta função pode ser chamado novamente dando origem a expressão argumento bem como o texto nos mostra. Este texto pode por sua vez contêm mais argumentos ou pode ser o parêntese de fechamento, que da termino a lista de argumentos. 69 | 70 | Esta é a primeira parte do analisador: 71 | 72 | ````javascript 73 | function parseExpression(program) { 74 | program = skipSpace(program); 75 | var match, expr; 76 | if (match = /^"([^"]*)"/.exec(program)) 77 | expr = {type: "value", value: match[1]}; 78 | else if (match = /^\d+\b/.exec(program)) 79 | expr = {type: "value", value: Number(match[0])}; 80 | else if (match = /^[^\s(),"]+/.exec(program)) 81 | expr = {type: "word", name: match[0]}; 82 | else 83 | throw new SyntaxError("Unexpected syntax: " + program); 84 | 85 | return parseApply(expr, program.slice(match[0].length)); 86 | } 87 | 88 | function skipSpace(string) { 89 | var first = string.search(/\S/); 90 | if (first == -1) return ""; 91 | return string.slice(first); 92 | } 93 | ```` 94 | 95 | Temos que remover os espaços em brancos repetidos no início de qualquer seqüência do programa pois o **Egg** permite qualquer quantidade de espaço em branco entre os seus elementos inseridos. Quem tem essa funcionalidade é a da funcão `skipSpace`. 96 | 97 | Depois de pular qualquer espaço à esquerda `parseExpression` usa três expressões regulares para detectar os três elementos simples(atômicas) que **Egg** suporta: `String`, `Number` e `words`. O analisador constrói um tipo diferente de estrutura de dados dependendo de sua correspondencia. Se a entrada não coincide com uma destas três formas não será considerado uma expressão válida e o analisador gerara um erro. `SyntaxError` é um tipo de erro padrão de objeto que é gerado quando é feita uma tentativa de executar um programa em JavaScript inválido. 98 | 99 | Podemos cortar algumas partes que nós comparamos a partir da seqüência e passar isso juntamente com o objeto para a expressão do `parseApply` que ira verificar se a expressão é uma aplicação. Se assim for ele analisa uma lista de argumentos entre parênteses. 100 | 101 | ````javascript 102 | function parseApply(expr, program) { 103 | program = skipSpace(program); 104 | if (program[0] != "()" 105 | return {expr: expr, rest: program}; 106 | 107 | program = skipSpace(program.slice(1)); 108 | expr = {type: "apply", operator: expr, args: []}; 109 | while (program[0] != ")") { 110 | var arg = parseExpression(program); 111 | expr.args.push(arg.expr); 112 | program = skipSpace(arg.rest); 113 | if (program[0] == ",") 114 | program = skipSpace(program.slice(1)); 115 | else if (program[0] != ")") 116 | throw new SyntaxError("Expected ',' or ')'"); 117 | } 118 | return parseApply(expr, program.slice(1)); 119 | } 120 | ```` 121 | 122 | Se o próximo caracter no programa não é um parêntese de abertura, este não é aplicável, e `parseApply` simplesmente retorna que a expressão foi proferida. 123 | 124 | Caso contrário ele ignora o parêntese de abertura e cria o objeto na árvore de sintaxe para essa expressão aplicável. Em seguida ele chama recursivamente `parseExpression` para analisar cada argumento até o parêntese de fechamento ser encontrado. A recursividade é indireta através da função `parseApply` e `parseExpression` chamando uns aos outros. 125 | 126 | Uma expressão de aplicação pode ser aplicado em si própria(como em `multiplier(2)(1)`); `parseApply` deve analisar um pedido depois chamar-se novamente para verificar se existe outro par de parênteses. 127 | 128 | Isso é tudo que precisamos para o analisador do **Egg**. Nós vamos envolvê-lo em uma função de análise conveniente que verifica se ele chegou ao fim da cadeia de entrada após o análise da expressão(um programa de **Egg** é uma única expressão) e que nos dá estrutura de dados do programa. 129 | 130 | ````javascript 131 | function parse(program) { 132 | var result = parseExpression(program); 133 | if (skipSpace(result.rest).length > 0) 134 | throw new SyntaxError("Unexpected text after program"); 135 | return result.expr; 136 | } 137 | 138 | console.log(parse("+(a, 10)")); 139 | // → {type: "apply", 140 | // operator: {type: "word", name: "+"}, 141 | // args: [{type: "word", name: "a"}, 142 | // {type: "value", value: 10}]} 143 | ```` 144 | 145 | Funcionou! Ele não nos dá informação muito útil quando há falhas e não armazena a linha e coluna na qual cada expressão começa, o que pode ser útil ao relatar erros mais tarde mas é bom o suficiente para nossos propósitos. 146 | 147 | ## O avaliador 148 | 149 | O que podemos fazer com uma árvore de sintaxe de um programa? Executá-lo é claro! E é isso que o avaliador faz. Você entrega-lhe uma árvore de sintaxe e um objeto do `environment` que associa nomes com os valores, e ele irá avaliar a expressão que a árvore representa e retornar o valor que esta produz. 150 | 151 | ````js 152 | function evaluate(expr, env) { 153 | switch(expr.type) { 154 | case "value": 155 | return expr.value; 156 | 157 | case "word": 158 | if (expr.name in env) 159 | return env[expr.name]; 160 | else 161 | throw new ReferenceError("Undefined variable: " + 162 | expr.name); 163 | case "apply": 164 | if (expr.operator.type == "word" && 165 | expr.operator.name in specialForms) 166 | return specialForms[expr.operator.name](expr.args, 167 | env); 168 | var op = evaluate(expr.operator, env); 169 | if (typeof op != "function") 170 | throw new TypeError("Applying a non-function."); 171 | return op.apply(null, expr.args.map(function(arg) { 172 | return evaluate(arg, env); 173 | })); 174 | } 175 | } 176 | 177 | var specialForms = Object.create(null); 178 | ```` 179 | 180 | O avaliador possui código para cada um dos tipos de expressão. A expressão de valor literal simplesmente produz o seu valor(por exemplo, a expressão 100 apenas avalia para o número 100). Para uma variável é preciso verificar se ele está realmente definido no `environment atual`, se estiver, buscar o valor da variável. 181 | 182 | As aplicações são mais envolvidas. Se eles são de uma forma especial, nós não avaliamos nada e simplesmente passamos as expressões como argumento junto com o `environment` para a função que lida com essa forma. Se for uma chamada normal nós avaliamos o operador verificamos se ele é uma função e chamamos com o resultado da avaliação dos argumentos. 183 | 184 | Iremos usar os valores de uma função simples em JavaScript para representar os valores de função em **Egg**. Voltaremos a falar sobre isso mais tarde quando o `specialForm` chamado `fun` estiver definido. 185 | 186 | A estrutura recursiva de um avaliador se assemelha à estrutura de um analisador. Ambos espelham a estrutura da própria linguagem. Além disso, seria possível integrar o analisador com o avaliador e avaliar durante a análise, mas dividindo-se desta forma torna o programa mais legível. 187 | 188 | Isso é tudo que precisamos para interpretar Egg. É simples assim. Mas sem definir algumas formas especiais e adicionar alguns valores úteis para o `environment` você não pode fazer nada com essa linguagem ainda. 189 | 190 | ## Formas especiais 191 | 192 | O objecto `specialForms` é utilizado para definir sintaxe especial em **Egg**. Ele associa palavras com funções que avaliam essas formas especiais. Atualmente ele está vazio. Vamos adicionar algumas formas. 193 | 194 | ````javascript 195 | specialForms["if"] = function(args, env) { 196 | if (args.length != 3) 197 | throw new SyntaxError("Bad number of args to if"); 198 | 199 | if (evaluate(args[0], env) !== false) 200 | return evaluate(args[1], env); 201 | else 202 | return evaluate(args[2], env); 203 | }; 204 | ```` 205 | 206 | **Egg** - `if` espera exatamente três argumentos. Ele irá avaliar o primeiro, se o resultado não é o valor falso ele irá avaliar a segunda. Caso contrário a terceira fica avaliada. Esta é a forma mais semelhante ao ternário do JavaScript `?:` estes operadores tem o mesmo significado de `if/else` em JavaScript. Isso é uma expressão e não uma indicação que produz um valor, ou seja, o resultado do segundo ou terceiro argumento. 207 | 208 | **Egg** difere de JavaScript na forma de como ele lida com o valor de um condição como o valor do `if`. Ele não vai tratar as coisas como zero ou cadeia vazia como falsa, somente valorores precisos são falsos. 209 | 210 | A razão especial é que nós preciso representar o `if` como uma forma especial, ao invés de uma função regular onde todos os argumentos para funções são avaliadas antes que a função seja chamada, ao passo que se deve avaliar apenas seu segundo ou terceiro argumento, dependendo do valor do primeiro. 211 | 212 | A forma `while` é semelhante. 213 | 214 | ````javascript 215 | specialForms["while"] = function(args, env) { 216 | if (args.length != 2) 217 | throw new SyntaxError("Bad number of args to while"); 218 | 219 | while (evaluate(args[0], env) !== false) 220 | evaluate(args[1], env); 221 | 222 | // Since undefined does not exist in Egg, we return false, 223 | // for lack of a meaningful result. 224 | return false; 225 | }; 226 | ```` 227 | 228 | Outro bloco na construção básico é fazer que executa todos os seus argumentos de cima para baixo. O seu valor é o valor produzido pelo último argumento. 229 | 230 | ````javascript 231 | specialForms["do"] = function(args, env) { 232 | var value = false; 233 | args.forEach(function(arg) { 234 | value = evaluate(arg, env); 235 | }); 236 | return value; 237 | }; 238 | ```` 239 | 240 | Para ser capaz de criar variáveis e dar-lhes novos valores, vamos criar um `specialForms` chamado `define`. Ele espera uma palavra como primeiro argumento de uma expressão que produz o valor a ser atribuído a essa palavra que sera seu segundo argumento. Vamos definir sendo tudo uma expressão e ela deve retornar um valor. Vamos fazê-lo retornar o valor que foi atribuído(igual ao operador `=` de JavaScript). 241 | 242 | ````javascript 243 | specialForms["define"] = function(args, env) { 244 | if (args.length != 2 || args[0].type != "word") 245 | throw new SyntaxError("Bad use of define"); 246 | var value = evaluate(args[1], env); 247 | env[args[0].name] = value; 248 | return value; 249 | }; 250 | ```` 251 | 252 | ## Ambiente 253 | 254 | O `environment` aceita avaliar um objeto com propriedades cujos nomes correspondem aos nomes de variáveis e cujos valores correspondem aos valores dessas variáveis. Vamos definir um objeto no environment para representar o escopo global. 255 | 256 | Para ser capaz de usar `if` que acabamos de definir teremos de ter acesso aos valores `booleanos`. Uma vez que existem apenas dois valores `booleanos` nós não precisamos de sintaxe especial para eles. Nós simplesmente vamos ligar duas variáveis em `topEnv` para os valores verdadeiros e falsos e dai então usá-los. 257 | 258 | ````javascript 259 | var topEnv = Object.create(null); 260 | 261 | topEnv["true"] = true; 262 | topEnv["false"] = false; 263 | ```` 264 | 265 | Agora podemos avaliar uma expressão simples que nega um valor `booleano`. 266 | 267 | ````javascript 268 | var prog = parse("if(true, false, true)"); 269 | console.log(evaluate(prog, topEnv)); 270 | // → false 271 | ```` 272 | 273 | Para suprir os operadores aritméticos e comparações básicas vamos adicionar alguns valores para função de `environment`. No interesse de manter um código pequeno vamos utilizar uma nova função para sintetizar um monte de funções de operador em um loop ao invéz de definir todos eles individualmente. 274 | 275 | ````javascript 276 | ["+", "-", "*", "/", "==", "<", ">"].forEach(function(op) { 277 | topEnv[op] = new Function("a, b", "return a " + op + " b;"); 278 | }); 279 | ```` 280 | 281 | É muito útil fazer uma maneira para que valores de saída sejam vizualidos, por isso vamos colocar alguns `console.log` na função e executa-lo para imprimir. 282 | 283 | ````javascript 284 | topEnv["print"] = function(value) { 285 | console.log(value); 286 | return value; 287 | }; 288 | ```` 289 | 290 | Isso ja nos proporcionou uma ferramenta elementar e suficiente para escrever programas simples. A seguinte função `run` fornece uma maneira conveniente de escrever e executá-los. Ele cria um `enviroment` em tempo real, analisa e avalia as `String` que damos como um programa único. 291 | 292 | ````javascript 293 | function run() { 294 | var env = Object.create(topEnv); 295 | var program = Array.prototype.slice 296 | .call(arguments, 0).join("\n"); 297 | return evaluate(parse(program), env); 298 | } 299 | ```` 300 | 301 | O uso de `Array.prototype.slice.call` é um truque para transformar um objeto de matriz como argumentos em uma matriz real; de modo que podemos chamar e juntar cada pedaço. 302 | No exemplo abaixo iremos percorrer todos os argumentos dados e tratar cada linha do programa. 303 | 304 | ````javascript 305 | run("do(define(total, 0),", 306 | " define(count, 1),", 307 | " while(<(count, 11),", 308 | " do(define(total, +(total, count)),", 309 | " define(count, +(count, 1)))),", 310 | " print(total))"); 311 | // → 55 312 | ```` 313 | 314 | Este é o programa que já vimos várias vezes antes que calcula a soma dos números de 1 a 10 escrito em **Egg**. É evidente que é mais feio do que um programa em JavaScript, mas não é tão ruim para uma linguagem implementada em menos de 150 linhas de código. 315 | 316 | ## Funções 317 | 318 | A linguagem de programação sem funções é uma linguagem de programação pobre. 319 | 320 | Felizmente, não é difícil para adicionar `fun` a nossa linguagem, que vai tratar todos os argumentos antes do último como nomes de argumentos da função e seu último argumento como corpo da função. 321 | 322 | ````javascript 323 | specialForms["fun"] = function(args, env) { 324 | if (!args.length) 325 | throw new SyntaxError("Functions need a body"); 326 | function name(expr) { 327 | if (expr.type != "word") 328 | throw new SyntaxError("Arg names must be words"); 329 | return expr.name; 330 | } 331 | var argNames = args.slice(0, args.length - 1).map(name); 332 | var body = args[args.length - 1]; 333 | 334 | return function() { 335 | if (arguments.length != argNames.length) 336 | throw new TypeError("Wrong number of arguments"); 337 | var localEnv = Object.create(env); 338 | for (var i = 0; i < arguments.length; i++) 339 | localEnv[argNames[i]] = arguments[i]; 340 | return evaluate(body, localEnv); 341 | }; 342 | }; 343 | ```` 344 | 345 | Funções em **Egg** tem seu próprio `enviroment` local assim como em JavaScript. Usamos `Object.create` para fazer um novo objeto que tem acesso às variáveis do ambiente externo(`prototype`) mas que também pode conter novas variáveis sem modificar esse escopo exterior. 346 | 347 | A função criada pela `especialForm` `fun` cria em ambito local e adiciona as variáveis de argumento para isso. Em seguida ele avalia o corpo da função neste ambiente e retorna o resultado. 348 | 349 | ````javascript 350 | run("do(define(plusOne, fun(a, +(a, 1))),", 351 | " print(plusOne(10)))"); 352 | // → 11 353 | 354 | run("do(define(pow, fun(base, exp,", 355 | " if(==(exp, 0),", 356 | " 1,", 357 | " *(base, pow(base, -(exp, 1)))))),", 358 | " print(pow(2, 10)))"); 359 | // → 1024 360 | ```` 361 | 362 | ## Compilação 363 | 364 | O que nós construímos foi um intérprete. Durante a avaliação ele age diretamente sobre a representação do programa produzido pelo analisador. 365 | 366 | A compilação é o processo de adicionar mais um passo entre a análise e a execução de um programa; que transforma o programa em algo que possa ser avaliado de forma mais eficiente fazendo o trabalho tanto quanto possível com antecedência. 367 | Por exemplo, em línguas bem desenhadas, é óbvio para cada uso de uma variável ele verifica qual esta se referindo sem realmente executar o programa. Isso pode ser usado para evitar a procura de uma variável pelo nome sempre que é acessado ou buscado diretamente de algum local pré-determinado da memória. 368 | 369 | Tradicionalmente, compilação envolve a conversão do programa para código de máquina no formato `raw` que o processador de um computador pode executar. Qualquer processo que converte um programa de uma representação diferente pode ser encarado como compilação. 370 | 371 | Seria possível escrever uma estratégia de avaliação alternativa para **Egg**, aquele que primeiro converte o programa para um programa JavaScript utilizando a nova função para chamar o compilador JavaScript, e em seguida executar o resultado. Sendo feito assim **Egg** executaria muito mais rápido e continuaria bastante simples de implementar. 372 | 373 | Se você está interessado e disposto neste assunto gaste algum tempo com isso, encorajo-vos a tentar implementar um compilador nos exercícios. 374 | 375 | ## Cheating 376 | 377 | Quando definimos `if` e `while`, você provavelmente percebeu que eles eram invólucros triviais em torno do próprio JavaScript. Da mesma forma, os valores em **Egg** são antigos valores de JavaScript. 378 | 379 | Se você comparar a execução de **Egg** que foi construída em alto nível utilizando a ajuda de JavaScript com a quantidade de trabalho e complexidade necessários para construir uma linguagem de programação utilizando diretamente a funcionalidade `raw` fornecido por uma máquina essa diferença é enorme. Independentemente disso este é apenas um exemplo; espero ter lhe dado uma impressão de que maneira as linguagens de programação trabalham. 380 | 381 | E quando se trata de conseguir fazer algo, o `cheating` é o jeito mais eficaz de fazer tudo sozinho. Embora a linguagem que brincamos neste capítulo não faz nada de melhor que o JavaScript possui, existem situações em que a escrever pequenas línguas ajuda no entendimento verdadeiro do trabalho. 382 | 383 | Essa língua não possui semelhanças com uma linguagem típica de programação. Se o JavaScript não vêm equipado com expressões regulares você pode escrever seu próprio analisador e avaliador para tal sub linguagem. 384 | 385 | Ou imagine que você está construindo um dinossauro robótico gigante e precisa programar o seu comportamento. JavaScript pode não ser a forma mais eficaz de fazer isso. Você pode optar por uma linguagem que se parece com isso: 386 | 387 | ````javascript 388 | behavior walk 389 | perform when 390 | destination ahead 391 | actions 392 | move left-foot 393 | move right-foot 394 | 395 | behavior attack 396 | perform when 397 | Godzilla in-view 398 | actions 399 | fire laser-eyes 400 | launch arm-rockets 401 | ```` 402 | 403 | Isto é o que geralmente é chamado de linguagem de domínio específica, uma linguagem adaptada para expressar um estreito conhecimento de um domínio. Essa linguagem pode ser mais expressiva do que uma linguagem de um propósito geral. Isto porque ela é projetada para expressar exatamente as coisas que precisam serem expressadas no seu domínio e nada mais. 404 | 405 | --- 406 | 407 | # Exercícios 408 | 409 | ## Arrays 410 | 411 | Adicionar suporte para `array` em **Egg** construindo as três funções em `topEnv` do escopo: `array(...)` vai ser a construção de uma matriz contendo os argumentos como valores, `length(array)` para obter o comprimento de um `array` e `element(array, n)` buscar `n` elementos de uma matriz. 412 | 413 | 414 | ````javascript 415 | // Modify these definitions... 416 | 417 | topEnv["array"] = "..."; 418 | 419 | topEnv["length"] = "..."; 420 | 421 | topEnv["element"] = "..."; 422 | 423 | run("do(define(sum, fun(array,", 424 | " do(define(i, 0),", 425 | " define(sum, 0),", 426 | " while(<(i, length(array)),", 427 | " do(define(sum, +(sum, element(array, i))),", 428 | " define(i, +(i, 1)))),", 429 | " sum))),", 430 | " print(sum(array(1, 2, 3))))"); 431 | // → 6 432 | ```` 433 | 434 | **Dica:** 435 | 436 | A maneira mais fácil de fazer isso é representar as matrizes de **Egg** atravéz de matrizes do JavaScript. 437 | 438 | Os valores adicionados ao `enviroment` no `topEnv` deve ser uma funções. `Array.prototype.slice`; pode ser utilizado para converter um `array` em um `object` de argumentos numa matriz regular. 439 | 440 | [**Resolução**](https://gist.github.com/SauloSilva/7bef8ec6e6f9abd9529a#file-egg-js-L170) 441 | 442 | ## Closures 443 | 444 | A maneira que definimos o `fun` é permitido que as funções em **Egg** se chamem em ambiente circundante, permitindo o corpo da função utilizar valores locais que eram visíveis no momento que a função foi definida, assim como as funções em JavaScript fazem. 445 | 446 | O programa a seguir ilustra isso: função `f` retorna uma função que adiciona o seu argumento ao argumento de f, o que significa que ele precisa de acesso ao escopo local dentro de `f` para ser capaz de utilizar a variável. 447 | 448 | ````js 449 | run("do(define(f, fun(a, fun(b, +(a, b)))),", 450 | "print(f(4)(5)))"); 451 | // → 9 452 | ```` 453 | 454 | Volte para a definição da forma `fun` e explique qual o mecanismo feito para que isso funcione. 455 | 456 | **Dica:** 457 | 458 | Mais uma vez, estamos cavalgando sobre um mecanismo de JavaScript para obter a função equivalente em **Egg**. Formas especiais são passados para o `enviroment` local de modo que eles possam ser avaliados pelas suas sub-formas do `enviroment`. A função retornada por `fun` se fecha sobre o argumento `env` dada a sua função de inclusão e usa isso para criar `enviroment` local da função quando é chamado. 459 | 460 | Isto significa que o `prototype` do `enviroment` local será o `enviroment` em que a função foi criado, o que faz com que seja possível ter acesso as variáveis de `enviroment` da função. Isso é tudo o que há para implementar e finalizar(embora para compilá-lo de uma forma que é realmente eficiente, você precisa de um pouco mais de trabalho). 461 | 462 | ## Comentários 463 | 464 | Seria bom se pudéssemos escrever comentários no **Egg**. Por exemplo, sempre que encontrar um cardinal `("#")`, poderíamos tratar o resto da linha como um comentário e ignorá-lo, semelhante que Javascript faz com o `"//"`. 465 | 466 | Não temos de fazer quaisquer grandes mudanças para que o analisador suporte isto. Nós podemos simplesmente mudar o `skipSpace` para ignorar comentários assim como é feito com os espaços em branco; para que todos os pontos onde `skipSpace` é chamado agora também ira ignorar comentários. Vamos fazer essa alteração: 467 | 468 | ````javascript 469 | // This is the old skipSpace. Modify it... 470 | function skipSpace(string) { 471 | var first = string.search(/\S/); 472 | if (first == -1) return ""; 473 | return string.slice(first); 474 | } 475 | 476 | console.log(parse("# hello\nx")); 477 | // → {type: "word", name: "x"} 478 | 479 | console.log(parse("a # one\n # two\n()")); 480 | // → {type: "apply", 481 | // operator: {type: "word", name: "a"}, 482 | // args: []} 483 | ```` 484 | 485 | **Dica:** 486 | 487 | Certifique-se de que sua solução é válida com vários comentários em uma linha e principalmente com espaço em branco entre ou depois deles. 488 | 489 | Uma expressão regular é a maneira mais fácil de resolver isso. Faça algo que corresponda "espaços em branco ou um comentário, uma ou mais vezes". Use o método `exec` ou `match` para olhar para o comprimento do primeiro elemento na matriz retornada(desde de o inicio) para saber quantos caracteres precisa para cortar. 490 | 491 | [**Resolução**](https://gist.github.com/SauloSilva/7bef8ec6e6f9abd9529a#file-egg-js-L17) 492 | 493 | ## Corrigindo o escopo 494 | 495 | Atualmente, a única maneira de atribuir uma variável um valor é utilizando o método `define`. Esta construção atua tanto como uma forma para definir novas variáveis e dar um novo valor para existentes. 496 | 497 | Isto causa um problema de ambiguidade. Quando você tenta dar uma variável um novo valor que não esta local, você vai acabar definindo uma variável local com o mesmo nome em seu lugar(Algumas línguas funcionam assim por design, mas eu sempre achei uma maneira estranha de lidar com escopo). 498 | 499 | Adicionar um `specialForm` similar ao `define` dara a variável um novo valor ou a atualização da variável em um escopo exterior se ele ainda não existir no âmbito interno. Se a variável não é definida em tudo lançar um `ReferenceError`(que é outro tipo de erro padrão). 500 | 501 | A técnica de representar escopos como simples objetos tornou as coisas convenientes, até agora, e vai ficar um pouco no seu caminho neste momento. Você pode querer usar a função `Object.getPrototypeOf` que retorna os protótipos de um objeto. Lembre-se também que os escopos não derivam de `Object.prototype`, por isso, se você quiser chamar `hasOwnProperty` sobre eles,você tera que usar esta expressão não muito elegante: 502 | 503 | ````javascript 504 | Object.prototype.hasOwnProperty.call(scope, name); 505 | ```` 506 | 507 | Este método(`hasOwnProperty`) busca o protótipo do objeto e depois chama-o em um objeto do escopo. 508 | 509 | ````javascript 510 | specialForms["set"] = function(args, env) { 511 | // Your code here. 512 | }; 513 | 514 | run("do(define(x, 4),", 515 | " define(setx, fun(val, set(x, val))),", 516 | " setx(50),", 517 | " print(x))"); 518 | // → 50 519 | run("set(quux, true)"); 520 | // → Some kind of ReferenceError 521 | ```` 522 | 523 | **Dica:** 524 | 525 | Você vai ter que percorrer um escopo de cada vez usando `Object.getPrototypeOf` ate ir ao escopo externo. Para cada um dos escopos use `hasOwnProperty` para descobrir se a variável indicado pela propriedade `name` do primeiro argumento definida existe nesse escopo. Se isso acontecer defina-o como o resultado da avaliação do segundo argumento, e em seguida retorne esse valor. 526 | 527 | Se o escopo mais externo é atingido(`Object.getPrototypeOf` retornando `null`) e não encontramos a variável, isto significa que não existe; então um erro deve ser acionado. 528 | 529 | [**Resolução**](https://gist.github.com/SauloSilva/7bef8ec6e6f9abd9529a#file-egg-js-L156) 530 | -------------------------------------------------------------------------------- /chapters/12-javascript-e-o-navegador.md: -------------------------------------------------------------------------------- 1 | # JavaScript e o Navegador 2 | 3 | > "O navegador é um ambiente realmente hostil de programação." 4 | > 5 | > - Douglas Crockford, The JavaScript Programming Language (video lecture) 6 | 7 | A próxima parte deste livro vai falar sobre os navegadores web. Sem os navegadores, não existiria JavaScript. E mesmo se existisse, ninguém daria atenção a ele. 8 | 9 | A tecnologia web, desde de o início, é descentralizada não apenas tecnicamente mas também na maneira que se evolui. Vários fornecedores de navegador tem adicionado funcionalidades *ad-hoc* e muita das vezes tem sido de maneiras mal pensadas, que acabam sendo adotadas por outros e finalmente viram um padrão. 10 | 11 | Isso é igualmente a uma benção e uma maldição. Por outro lado, isso reforça a não existência de uma particição central controlando um sistema mas o mesmo vem sendo melhorado por várias partes trabalhando com pouca colaboração (ou, ocasionalmente com franca hostilidade). Sendo assim a forma casual que a Web foi desenvolvida significa que o sistema resultante não é exatamente um brilhante exemplo interno de consistência. De fato, algumas partes são completamente bagunçadas e confusas. 12 | 13 | ## Redes e a Internet 14 | 15 | Redes de computador existem desde 1950. Se você colocar cabos entre dois ou mais computadores e permitir que eles enviem dados um para o outro por estes cabos, você pode fazer todo tipo de coisas maravilhosas. 16 | 17 | Se conectando duas máquinas no mesmo prédio permite que nós façamos coisas incríveis, conectando máquinas por todo o planeta deve ser ainda melhor. A tecnologia para começar a implementação desta visão foi desenvolvida em meados de 1980, e a rede resultante é chamada de *Internet*. Ela tem vivido desde a sua promessa. 18 | 19 | Um computador pode usar essa rede para enviar bits para outro computador. Para qualquer comunicação efetiva nascida desse envio de bits, os computadores em ambas as pontas devem conhecer qual a representação de cada bit. O significado de cada sequência de bits depende inteiramente do tipo de coisa que está tentando se expressar e o mecanismo de codificação usado. 20 | 21 | Um *protocolo de rede* descreve um estilo de comunicação em uma rede. Existem protocolos para mandar email, para receber email, para transferir arquivos, e até mesmo para controlar computadores que foram infectados por softwares maliciosos. 22 | 23 | Por exemplo, um simples protocolo de chat deve consistir em um computador enviando os bits que representam o texto "CHAT?" para outra máquina, e o outro respondendo "OK!" para confirmar que o protocolo foi entendido. Eles podem então proceder e enviar um para o outro `strings` de texto, ler o texto enviado um para o outro pela rede, e mostrar o que eles receberam nas suas telas. 24 | 25 | A maioria dos protocolos são feitos em cima de outros protocolos. Nosso exemplo de protocolo de chat considera a rede como um tipo de dispositivo de *stream*, no qual você pode enviar bits e recebê-los com destino correto e na ordem correta. Assegurar essas coisas atualmente é um problema técnico bastante difícil. 26 | 27 | O TCP (Protocolo de Controle de Transmissão) é um protocolo que resolve este problema. Todos os aparelhos conectados na Internet "falam" ele, e a maioria da comunicação na Internet é feita através dele. 28 | 29 | Uma conexão TCP funciona da seguinte maneira: um computador deve estar esperando, ou *ouvindo*, outros computadores que irão começar a falar com ele. Para ser capaz de escutar por diferentes tipos de comunicação ao mesmo tempo em uma única máquina, cada *ouvinte* tem um número (chamado de **porta**) associado a ele. A maioria dos protocolos especificam qual porta deve ser usada por padrão. Por exemplo, quando nós queremos mandar um email usando o protocolo SMTP, a máquina pelo qual enviaremos deve estar escutando na porta 25. 30 | 31 | Outro computador pode então estabelecer uma conexão se conectando na máquina alvo usando o número correto da porta. Se a máquina alvo pode ser encontrada e estiver escutando esta porta, a conexão vai ser criada com sucesso. O computador ouvinte é chamado de servidor, e o computador que está se conectando é chamado de cliente. 32 | 33 | Uma conexão atua como um encanamento de via dupla pelo qual bits podem ser transitados às máquinas nas duas extremidades contendo dados. Uma vez que os bits tenham sido transmitidos com sucesso, eles podem ser lidos novamente pela máquina do outro lado. Isso é um modelo conveniente. Você pode dizer que o TCP fornece uma abstração de uma rede. 34 | 35 | ## A Web 36 | 37 | A *World Wide Web* (não ser confundida com a Internet como um todo) é um conjunto de protocolos e formatos que nos permite visitar páginas web em um navegador. A parte "Web" no nome se refere ao fato destas páginas serem facilmente ligadas umas nas outras, e então se ligarem em uma grande malha onde os usuários podem se mover através desta. 38 | 39 | Para adicionar conteúdo na Web, tudo que você precisa fazer é conectar uma máquina a Internet, e deixá-la escutando na porta 80, usando o *Hypertext Transfer Protocol* (HTTP). Este protocolo permite outros computadores requisitarem documentos na rede. 40 | 41 | Cada documento na Web é nomeado por um *Universal Resource Locator* (URL), que se parece com algo assim: 42 | 43 | ``` 44 | http://eloquentjavascript.net/12_browser.html 45 | | | | | 46 | protocolo servidor caminho (path) 47 | ``` 48 | 49 | A primeira parte nos diz que esta URL usa o protocolo HTTP (ao contrário, por exemplo, do HTTP encriptado, que deve ser `https://`). Então vem a parte que identifica de qual servidor nós estamos requisitando o documento. Por último temos a string de caminho que identifica o documento específico (ou *resource*) que estamos interessados. 50 | 51 | Cada máquina conectada com a Internet recebe um *endereço IP* único, que se parece com `37.187.37.82`. Você pode usar isso diretamente como parte da URL. Porém listas de números mais ou menos aleatórios são difíceis de lembrar e estranho de se digitar, então ao invés disso você pode registrar um *nome de domínio* para apontar para uma máquina específica ou conjunto de máquinas. Eu registrei *eloquentjavascript.net* para apontar para o endereço IP da máquina que eu controlo e posso então usar o nome do domínio para servir páginas da web. 52 | 53 | Se você digitar a URL anterior na barra de endereços do seu navegador, ela vai tentar retornar e mostrar o documento dessa URL. Primeiro, seu navegador tem que encontrar qual endereço *eloquentjavascript.net* se refere. Então, usando o protocolo HTTP, ele faz a conexão ao servidor neste endereço e pergunta pelo documento */12_browser.html*. 54 | 55 | Vamos ver com mais detalhes sobre o protocolo HTTP no capítulo 17. 56 | 57 | ## HTML 58 | 59 | HTML, que significa *Hypertext Markup Language (Linguagem de marcação de hipertexto)*, é o formato de documento usado para as páginas web. Um documento HTML contém texto, bem como *tags* que fornecem estrutura para esse texto, descrevendo coisas como links, parágrafos e cabeçalhos. 60 | 61 | Um documento HTML simples, se parece com este: 62 | 63 | ```html 64 | 65 | 66 | 67 | My home page 68 | 69 | 70 |

My home page

71 |

Hello, I am Marijn and this is my home page.

72 |

I also wrote a book! Read it 73 | here.

74 | 75 | 76 | ``` 77 | 78 | As *tags*, definidas entre os sinais de menor e maior que (< e >), fornecem informações sobre a estrutura do documento. O conteúdo restante é apenas texto puro. 79 | 80 | O documento começa com ``, que diz ao navegador para interpretá-lo como HTML *moderno* (HTML5), ao invés de outras versões que foram usadas no passado. 81 | 82 | Documentos HTML possuem um `head` (cabeça) e um `body` (corpo). O `head` contém informações *sobre* o documento, o `body` contém o documento em si. Neste caso, nós primeiro declaramos que o título do documento é *"My home page"* e em seguida, declaramos o `body` contendo um cabeçalho (`

`, que significa *"heading 1"* - As *tags* de `

` a `

` produzem cabeçalhos menores) e dois parágrafos (`

`). 83 | 84 | *Tags* aparecem em diversas formas. Um elemento, como o ``, um parágrafo ou um link, começa com uma *tag* de abertura como em `

` e termina com uma *tag* de fechamento como em `

`. Algumas *tags* de abertura, como aquela para o link (``), contém informações extra na forma de pares `nome="valor"`. Estes são chamados de *atributos*. Nesse caso, o destino do link é indicado pelo atributo `href="http://eloquentjavascript.net"`, onde `href` significa "*hypertext reference*" (referência de hipertexto). 85 | 86 | Alguns tipos de *tags* não englobam conteúdo e assim não necessitam de uma *tag* de fechamento. Um exemplo seria ``, que irá mostrar a imagem encontrada na URL informada no atributo `src`. 87 | 88 | Para sermos capazes de incluir os sinais de menor e maior no texto de um documento, mesmo esses possuindo um significado especial em HTML, teremos que introduzir mais uma nova forma de notação especial. Uma *tag* de abertura simples é escrita como `<` ("*less than*" - menor que), e uma *tag* de fechamento é escrita como `>` ("*greater than*" - maior que). Em HTML, o caractere & (o sinal de "E comercial") seguido por uma palavra e um ponto e vírgula é chamado de "entidade" (*entity*), e será substituída pelo caractere que representa. 89 | 90 | Essa notação é parecida com a forma que as barras invertidas são utilizadas nas *strings* em JavaScript. Uma vez que esse mecanismo dá ao caractere `&` um significado especial, este tem que ser representado como `&`. Dentro que um atributo, que é definido entre aspas duplas, a entidade `"` pode ser usada para representar um caractere de aspas duplas. 91 | 92 | O HTML é interpretado de uma forma notavelmente tolerante a erros. Se uma *tag* é omitida, o navegador irá inseri-la. A forma com que isto é feito foi padronizada, você pode confiar em todos os navegadores modernos para realizar tal tarefa. 93 | 94 | O documento a seguir será tratado exatamente como o mostrado anteriormente: 95 | 96 | ```html 97 | 98 | 99 | My home page 100 | 101 |

My home page

102 |

Hello, I am Marijn and this is my home page. 103 |

I also wrote a book! Read it 104 | here. 105 | ``` 106 | 107 | As *tags* ``, `` e `` foram retiradas. O navegador sabe que a *tag* `` pertence ao `head`, e que `<h1>` pertence ao `body`. Além disso, eu não especifiquei o final dos parágrafos, o fato de começar um novo parágrafo ou fechar o documento irá implicitamente fechá-los. As aspas que envolviam o destino do link também foram retiradas. 108 | 109 | Esse livro geralmente vai omitir as tags `<html>`, `<head>` e `<body>` dos exemplos para mantê-los curtos e ordenados. Mas eu irei fechar as *tags* e incluir aspas nos valores de atributos. 110 | 111 | Eu geralmente também irei omitir o *doctype*. Isso não deve ser interpretado como um incentivo a omitir declarações de *doctype*. Os navegadores frequentemente irão fazer coisas ridículas quando você esquece delas. Você deve considerá-las implicitamente presentes nos exemplos, mesmo quando elas não forem mostradas no texto. 112 | 113 | ## HTML e JavaScript 114 | 115 | No contexto desse livro, a *tag* mais importante do HTML é `<script>`. Essa *tag* nos permite incluir trechos de JavaScript em um documento. 116 | 117 | ```html 118 | <h1>Testing alert</h1> 119 | <script>alert("hello!");</script> 120 | ``` 121 | 122 | Esse *script* será executado assim que a *tag* `<script>` for encontrada enquanto o navegador interpreta o HTML. A página mostrada acima irá exibir uma mensagem de alerta quando aberta. 123 | 124 | Incluir programas grandes diretamente no documento HTML é impraticável. A *tag* `<script>` pode receber um atributo `src` a fim de buscar um arquivo de *script* (um arquivo de texto contendo um programa em JavaScript) a partir de uma URL. 125 | 126 | ```html 127 | <h1>Testing alert</h1> 128 | <script src="code/hello.js"></script> 129 | ``` 130 | 131 | O arquivo `code/hello.js` incluído aqui contém o mesmo simples programa, `alert("hello!")`. Quando uma página HTML referencia outras URLs como parte de si, por exemplo um arquivo de imagem ou um *script*, os navegadores irão buscá-los imediatamente e incluí-los na página. 132 | 133 | Uma *tag* de *script* deve sempre ser fechada com `</script>`, mesmo quando fizer referência para um arquivo externo e não contenha nenhum código. Se você esquecer disso, o restante da página será interpretado como parte de um *script* . 134 | 135 | Alguns atributos podem conter um programa JavaScript. A *tag* `<button>` mostrada abaixo (que aparece como um botão na página) possui um atributo `onclick`, cujo conteúdo será executado sempre que o botão for clicado. 136 | 137 | ```html 138 | <button onclick="alert('Boom!');">DO NOT PRESS</button> 139 | ``` 140 | 141 | Perceba que eu tive que usar aspas simples para a *string* do atributo `onclick` porque aspas duplas já estão sendo usadas para envolver o valor do atributo. Eu também poderia ter usado `"`, mas isso tornaria o programa difícil de ler. 142 | 143 | ## Na caixa de areia 144 | 145 | Executar programas baixados da internet é potencialmente perigoso. Você não sabe muito sobre as pessoas por trás da maioria dos sites que visita e elas não necessariamente são bem intencionadas. Executar programas de pessoas que tenham más intenções é como ter seu computador infectado por vírus, seus dados roubados e suas contas *hackeadas*. 146 | 147 | Contudo, a atração da *Web* é que você pode navegar sem necessariamente confiar nas páginas que visita. Esse é o motivo pelo qual os navegadores limitam severamente as funções que um programa JavaScript pode fazer: eles não podem bisbilhotar os arquivos do seu computador ou modificar qualquer coisa que não esteja relacionada a página em que foi incorporado. 148 | 149 | O isolamento de um ambiente de programação dessa maneira é chamado de *sandboxing*, a ideia é que o programa é inofensivo "brincando" em uma "caixa de areia". Mas você deve imaginar esse tipo específico de caixas de areia como tendo sobre si uma gaiola de grossas barras de aço, o que as torna um pouco diferentes das caixas de areia típicas de *playgrounds*. 150 | 151 | A parte difícil do *sandboxing* é permitir que os programas tenham espaço suficiente para serem úteis e ao mesmo tempo impedi-los de fazer qualquer coisa perigosa. Várias funcionalidades úteis, como se comunicar com outros servidores ou ler o conteúdo da área de transferência, podem ser usadas para tarefas problemáticas ou invasivas à privacidade. 152 | 153 | De vez em quando, alguém aparece com uma nova forma de burlar as limitações de um navegador e fazer algo prejudicial, variando de vazamentos de alguma pequena informação pessoal até assumir o controle total da máquina onde o navegador está sendo executado. Os desenvolvedores de navegadores respondem "tapando o buraco", e tudo está bem novamente —até que o próximo problema seja descoberto e divulgado, ao invés de ser secretamente explorado por algum governo ou máfia. 154 | 155 | ## Compatibilidade e a guerra dos navegadores 156 | 157 | No início da web, um navegador chamado Mosaic dominava o mercado. Depois de alguns anos, quem desequilibrou a balança foi o Netscape, que por sua vez, foi derrotado pelo Internet Explorer da Microsoft. Nos momentos em que um único navegador era dominante, seus desenvolvedores se sentiam no direito de criar, unilateralmente, novas funcionalidades para a web. Como a maior parte dos usuários usava o mesmo navegador, os sites simplesmente começaram a usar esses recursos —sem se importarem com os outros navegadores. 158 | 159 | Essa foi a idade das trevas da compatibilidade, frequentemente chamada de "guerra dos navegadores". Os desenvolvedores web não tiveram uma web unificada, mas sim duas ou três plataformas incompatíveis. Para piorar as coisas, os navegadores usados por volta de 2003 eram cheios de *bugs*, e, é claro que esses *bugs* foram diferentes para cada navegador. A vida era difícil para aqueles que escreviam páginas web. 160 | 161 | O Mozilla Firefox, uma ramificação sem fins lucrativos do Netscape, desafiou a hegemonia do Internet Explorer no final dos anos 2000. A Microsoft não estava particularmente interessada em se manter competitiva nessa época, o Firefox levou uma parcela do mercado para longe do IE. Pela mesma época, a Google introduziu seu navegador Chrome, e o navegador Safari da Apple ganhou popularidade, levando-nos a uma situação onde existiam quatro grandes "competidores" nesse seguimento ao invés de um. 162 | 163 | Os novos navegadores possuíam uma postura mais séria sobre a questão dos padrões e de melhores práticas de engenharia, diminuindo as incompatibilidades e *bugs*. A Microsoft, vendo sua cota de mercado se esfarelar, começou a adotar essas atitudes. Se você está começando a aprender sobre desenvolvimento web hoje, considere-se com sorte. As últimas versões da maior parte dos navegadores se comportam de uma maneira uniforme e possuem relativamente menos *bugs*. 164 | 165 | Ainda não dá para dizer que a situação é perfeita. Algumas pessoas que usam a web estão, por motivo de inércia ou políticas corporativas, presas a navegadores antigos. Enquanto esses navegadores não "morrerem" completamente, desenvolver sites que funcionem para eles vai exigir uma grande quantidade de conhecimento "misterioso" sobre suas peculiaridades e defeitos. Este livro não tratará dessas peculiaridades. Pelo contrário, tem como objetivo apresentar um estilo de programação moderno e sensato. 166 | -------------------------------------------------------------------------------- /glossario.md: -------------------------------------------------------------------------------- 1 | # Glossário 2 | Essa página tem como objetivo reunir termos técnicos (ou não) e suas respectivas traduções para mantermos uma padrão uniforme nos capítulos. Esse é um documento orgânico que irá ser atualizado de forma colaborativa a medida que novos termos forem surgindo. 3 | 4 | # Traduções (Original - Tradução) 5 | 6 | * Debug - Debugar ([#155](https://github.com/braziljs/eloquente-javascript/issues/155)) 7 | * Writable stream - Stream de escrita ([#115](https://github.com/braziljs/eloquente-javascript/issues/115)) 8 | * Thread - Thread ([#98](https://github.com/braziljs/eloquente-javascript/issues/98)) 9 | * Callback - Callback ([#97](https://github.com/braziljs/eloquente-javascript/issues/97)) 10 | * Let’s get coding - Vamos codar ([#92](https://github.com/braziljs/eloquente-javascript/issues/92)) 11 | * Body - Corpo 12 | * Client - Cliente 13 | * Encoded - Codificado 14 | * Prefetch - Pré-carregar 15 | * Query String - String de pesquisa 16 | * Resource - Recurso 17 | * Request - Request 18 | * Response - Resposta 19 | * String - String 20 | * URL Encoding - Codificação da URL 21 | * Array - Array 22 | * Wrapper - Wrapper ([#273](https://github.com/braziljs/eloquente-javascript/issues/273)) 23 | 24 | ## Como contribuir? 25 | No arquivo [CONTRIBUTING.md](https://github.com/braziljs/eloquente-javascript/blob/master/CONTRIBUTING.md), há uma seção chamada **"Dúvidas em tradução de termos, palavras, expressões etc..."** explicando mais detalhes sobre como contribuir. Se você tem alguma sugestão para melhorar alguma tradução já feita, basta comentar na issue de referência sua sugestão que vamos discutir a proposta de alteração. 26 | -------------------------------------------------------------------------------- /img/alert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/alert.png -------------------------------------------------------------------------------- /img/bit-sea.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/bit-sea.png -------------------------------------------------------------------------------- /img/cap4_frac_sqrt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/cap4_frac_sqrt.png -------------------------------------------------------------------------------- /img/computer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/computer.png -------------------------------------------------------------------------------- /img/confirm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/confirm.png -------------------------------------------------------------------------------- /img/controlflow_if.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/controlflow_if.png -------------------------------------------------------------------------------- /img/controlflow_loop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/controlflow_loop.png -------------------------------------------------------------------------------- /img/controlflow_nested_if.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/controlflow_nested_if.png -------------------------------------------------------------------------------- /img/controlflow_straight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/controlflow_straight.png -------------------------------------------------------------------------------- /img/cos_sin.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="252" height="167" viewBox="-131 -84 252 167"><style> 3 | @font-face { 4 | font-family: 'PT Mono'; 5 | font-style: normal; 6 | font-weight: 400; 7 | src: local('PT Mono'), local('PTMono-Regular'), url(http://themes.googleusercontent.com/static/fonts/ptmono/v1/jmle3kzCPnW8O7_gZGRDlQ.woff) format('woff'); 8 | } 9 | .caption { font-family: 'PT Mono'; font-size: 13px; } 10 | </style> 11 | <g><path d="M 0.5 -79.5 L 0.5 80.5" stroke="black"></path><path d="M -79.5 0.5 L 80.5 0.5" stroke="black"></path><path d="M 14.7 3 A 15 15 0 1 1 10.6 -10.6" stroke="black" fill="none"></path><path d="M 12.5 -8.5 L 13.5 -7.5" stroke="black"></path><path d="M 0 0 L 3 8 L 0 7 L -3 8 Z" stroke="none" fill="rgb(0, 0, 0)" transform="translate(13.5 -7.5) rotate(135) scale(1)"></path><ellipse cx="0" cy="0" rx="60" ry="60" stroke="black" fill="none" width="120" height="120"></ellipse><ellipse cx="42.426406871192846" cy="42.426406871192846" rx="3" ry="3" fill="#44f" width="6" height="6"></ellipse><path d="M 0.5 42.5 L 39.5 42.5" stroke="#44f"></path><path d="M 0 0 L 3 8 L 0 7 L -3 8 Z" stroke="none" fill="rgb(68, 68, 255)" transform="translate(39.5 42.5) rotate(90) scale(1)"></path><path d="M 42.5 0.5 L 42.5 39.5" stroke="#44f"></path><path d="M 0 0 L 3 8 L 0 7 L -3 8 Z" stroke="none" fill="rgb(68, 68, 255)" transform="translate(42.5 39.5) rotate(180) scale(1)"></path><text x="32.426406871192846" y="64.42640687119285" class="caption" fill="#44f">cos(¼π)</text><text x="62.426406871192846" y="29.426406871192846" class="caption" fill="#44f">sin(¼π)</text><ellipse cx="-30.000000000544134" cy="-51.961524226752175" rx="3" ry="3" fill="#0a0" width="6" height="6"></ellipse><path d="M 0.5 -51.5 L -27.5 -51.5" stroke="#0a0"></path><path d="M 0 0 L 3 8 L 0 7 L -3 8 Z" stroke="none" fill="rgb(0, 170, 0)" transform="translate(-27.5 -51.5) rotate(270) scale(1)"></path><path d="M -30.5 0.5 L -30.5 -48.5" stroke="#0a0"></path><path d="M 0 0 L 3 8 L 0 7 L -3 8 Z" stroke="none" fill="rgb(0, 170, 0)" transform="translate(-30.5 -48.5) scale(1)"></path><text x="-84.00000000054413" y="-69.96152422675218" class="caption" fill="#0a0">cos(-⅔π)</text><text x="-129.00000000054413" y="-29.961524226752175" class="caption" fill="#0a0">sin(-⅔π)</text></g></svg> -------------------------------------------------------------------------------- /img/darkblue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/darkblue.png -------------------------------------------------------------------------------- /img/eloq-js.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/eloq-js.jpg -------------------------------------------------------------------------------- /img/eloq-js.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/eloq-js.png -------------------------------------------------------------------------------- /img/exercise_shapes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/exercise_shapes.png -------------------------------------------------------------------------------- /img/game_grid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/game_grid.png -------------------------------------------------------------------------------- /img/html-boxes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/html-boxes.jpg -------------------------------------------------------------------------------- /img/html-links.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/html-links.jpg -------------------------------------------------------------------------------- /img/html-tree.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/html-tree.jpg -------------------------------------------------------------------------------- /img/linked-list.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="393" height="76" viewBox="-2 -2 393 76"><style> 3 | @font-face { 4 | font-family: 'PT Mono'; 5 | font-style: normal; 6 | font-weight: 400; 7 | src: local('PT Mono'), local('PTMono-Regular'), url(http://themes.googleusercontent.com/static/fonts/ptmono/v1/jmle3kzCPnW8O7_gZGRDlQ.woff) format('woff'); 8 | } 9 | .objtext { font-family: "PT Mono"; font-size: 14px; stroke: none; } 10 | .objbox { border-radius: 2px; fill: white; stroke: black } 11 | .sep { stroke: #666 } 12 | </style> 13 | <g><g><rect x="0.5" y="0.5" width="104" height="51" class="objbox" rx="2" ry="2"></rect><text x="10" y="20" class="objtext">value: 1</text><text x="10" y="40" class="objtext">rest:</text></g><g><rect x="134.5" y="10.5" width="104" height="51" class="objbox" rx="2" ry="2"></rect><text x="144.5" y="30.5" class="objtext">value: 2</text><text x="144.5" y="50.5" class="objtext">rest:</text></g><path d="M 58.5 36.5 L 134.5 36.5" class="sep"></path><path d="M 0 0 L 3 8 L 0 7 L -3 8 Z" stroke="none" fill="rgb(102, 102, 102)" transform="translate(134.5 36.5) rotate(90) scale(1)"></path><g><rect x="268.5" y="20.5" width="120" height="51" class="objbox" rx="2" ry="2"></rect><text x="278.5" y="40.5" class="objtext">value: 3</text><text x="278.5" y="60.5" class="objtext">rest: null</text></g><path d="M 192.5 47.5 L 268.5 47.5" class="sep"></path><path d="M 0 0 L 3 8 L 0 7 L -3 8 Z" stroke="none" fill="rgb(102, 102, 102)" transform="translate(268.5 47.5) rotate(90) scale(1)"></path></g></svg> -------------------------------------------------------------------------------- /img/mirror.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/mirror.png -------------------------------------------------------------------------------- /img/mysterious-computer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/mysterious-computer.jpg -------------------------------------------------------------------------------- /img/object.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/object.jpg -------------------------------------------------------------------------------- /img/octopus-array.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/octopus-array.jpg -------------------------------------------------------------------------------- /img/octopus-object.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/octopus-object.jpg -------------------------------------------------------------------------------- /img/octopus.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/octopus.jpg -------------------------------------------------------------------------------- /img/pizza-squirrel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/pizza-squirrel.png -------------------------------------------------------------------------------- /img/pizza-squirrel.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 | <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="505" height="345" viewBox="-2 -2 505 345"><defs> 3 | <g id="squirrel"> 4 | <path d="M 30 0 C 13 0 0 14 0 31 C 0 41 5 50 13 55 C 13 55 13 55 13 54 C 13 49 17 44 22 44 C 22 44 24 44 24 45 C 26 45 29 47 30 51 C 30 55 30 60 28 63 L 28 63 C 28 64 26 65 26 67 C 26 69 25 71 25 72 C 25 73 25 73 25 73 C 25 73 25 73 25 73 C 24 85 29 96 39 99 C 42 100 43 100 46 99 C 38 94 36 83 39 74 C 42 69 46 65 50 60 C 54 56 57 50 59 44 C 59 40 61 36 61 32 C 61 32 61 32 61 32 C 61 32 61 31 61 31 C 61 14 47 0 30 0 z" fill="#ea4" stroke="none"></path> 5 | <path d="M 74 14 C 70 17 67 19 64 23 C 64 23 64 23 64 23 C 64 24 64 24 64 26 C 62 32 68 40 76 41 C 86 44 93 40 96 33 C 95 29 91 26 84 23 C 82 22 79 22 78 21 L 74 14 z M 79 26 C 80 26 82 27 82 28 C 82 29 80 31 79 31 C 78 31 76 29 76 28 C 76 27 78 26 79 26 z" fill="#ea4" stroke="none"></path> 6 | <path d="M 68 41 C 68 41 68 41 68 41 L 68 41 L 68 41 C 64 46 57 56 43 71 C 43 72 42 73 42 74 C 39 81 39 88 43 94 C 43 94 45 94 45 95 C 45 95 45 95 45 95 C 46 95 46 95 46 95 C 46 95 46 95 46 95 C 46 96 47 96 47 96 C 49 97 50 97 50 99 C 53 99 55 100 57 100 L 57 100 L 96 100 C 96 100 96 100 96 100 C 99 100 100 97 100 95 C 100 94 99 91 96 91 L 96 91 L 79 91 L 78 91 L 75 91 C 75 91 75 91 75 91 C 75 91 76 91 76 90 C 76 90 78 90 78 90 C 78 90 78 90 78 90 C 78 88 78 88 78 88 C 79 88 79 88 79 88 C 79 88 79 88 79 88 C 84 83 86 77 82 73 C 79 71 76 69 74 68 C 72 68 72 68 71 68 C 71 68 71 68 70 68 C 70 68 70 68 70 68 C 70 68 68 68 68 68 C 68 68 68 68 68 68 C 68 68 68 68 68 68 C 67 68 67 68 67 68 C 67 68 67 68 67 68 C 67 68 66 68 66 68 C 66 68 66 68 66 68 C 64 68 64 69 64 69 C 63 69 63 69 62 69 C 62 69 62 69 62 69 C 61 71 61 71 61 71 C 59 71 59 71 59 72 C 59 72 59 72 59 72 C 58 72 58 72 58 72 C 58 72 58 72 58 72 C 57 73 57 73 57 73 C 57 73 57 73 57 73 C 57 73 57 73 57 73 C 55 74 55 74 55 74 C 55 74 55 74 55 74 C 55 74 55 76 55 76 C 54 76 54 76 54 77 C 54 77 54 77 54 77 L 51 76 C 51 74 53 74 53 73 C 54 72 55 71 57 69 C 61 67 64 65 70 65 C 70 65 71 65 71 65 C 72 65 74 65 74 67 C 74 65 75 65 75 64 C 76 60 79 58 82 56 C 82 56 82 56 82 56 C 83 55 84 55 86 55 L 88 55 C 88 56 91 59 93 59 C 96 59 97 56 97 54 C 97 51 96 49 93 49 L 93 49 L 79 49 L 78 45 C 75 44 71 42 68 41 z" fill="#ea4" stroke="none"></path> 7 | </g> 8 | <g id="pizza"> 9 | <path d="M 4 96 L 74 38 A 92 92 0 0 0 4 4 Z" stroke="#b44" stroke-width="8" fill="none" stroke-linejoin="round"></path> 10 | <circle cx="20" cy="20" r="10" fill="#b44"></circle> 11 | <circle cx="40" cy="30" r="9" fill="#b44"></circle> 12 | <circle cx="15" cy="66" r="11" fill="#b44"></circle> 13 | <circle cx="12" cy="36" r="10" fill="#b44"></circle> 14 | <circle cx="37" cy="51" r="11" fill="#b44"></circle> 15 | <circle cx="62" cy="34" r="8" fill="#b44"></circle> 16 | </g> 17 | </defs> 18 | <g><g x="0" y="0" width="500" height="340"><path d="M 250 0 L 250 340" width="500" height="340" stroke-width="2" stroke="black"></path><path d="M 0 170 L 500 170" width="500" height="340" stroke-width="2" stroke="black"></path><rect x="0" y="0" width="500" height="340" stroke-width="2" stroke="black" fill="none"></rect></g><use x="35" y="20" opacity="0.3" xlink:href="#pizza"></use><use x="125" y="20" opacity="0.3" xlink:href="#squirrel"></use><text x="20" y="156" font-family="Georgia" font-size="17">No pizza, no squirrel</text><text x="196" y="153" font-family="Georgia" font-size="31">76</text><use x="35" y="190" opacity="0.3" xlink:href="#pizza"></use><use x="125" y="190" xlink:href="#squirrel"></use><text x="20" y="326" font-family="Georgia" font-size="17">No pizza, squirrel</text><text x="212" y="323" font-family="Georgia" font-size="31">4</text><use x="285" y="20" xlink:href="#pizza"></use><use x="375" y="20" opacity="0.3" xlink:href="#squirrel"></use><text x="270" y="156" font-family="Georgia" font-size="17">Pizza, no squirrel</text><text x="462" y="153" font-family="Georgia" font-size="31">9</text><use x="285" y="190" xlink:href="#pizza"></use><use x="375" y="190" xlink:href="#squirrel"></use><text x="270" y="326" font-family="Georgia" font-size="17">Pizza, squirrel</text><text x="467" y="323" font-family="Georgia" font-size="31">1</text></g></svg> -------------------------------------------------------------------------------- /img/player_big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/player_big.png -------------------------------------------------------------------------------- /img/prompt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/prompt.png -------------------------------------------------------------------------------- /img/re_porcogalinhas.svg: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8" standalone="no"?> 2 | <svg 3 | xmlns:dc="http://purl.org/dc/elements/1.1/" 4 | xmlns:cc="http://creativecommons.org/ns#" 5 | xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" 6 | xmlns:svg="http://www.w3.org/2000/svg" 7 | xmlns="http://www.w3.org/2000/svg" 8 | xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" 9 | xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" 10 | height="166.23486" 11 | version="1.1" 12 | width="618.75934" 13 | style="overflow:hidden" 14 | id="svg2" 15 | inkscape:version="0.48.4 r9939" 16 | sodipodi:docname="re_pigchickens.svg"> 17 | <metadata 18 | id="metadata110"> 19 | <rdf:RDF> 20 | <cc:Work 21 | rdf:about=""> 22 | <dc:format>image/svg+xml</dc:format> 23 | <dc:type 24 | rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> 25 | </cc:Work> 26 | </rdf:RDF> 27 | </metadata> 28 | <sodipodi:namedview 29 | pagecolor="#ffffff" 30 | bordercolor="#666666" 31 | borderopacity="1" 32 | objecttolerance="10" 33 | gridtolerance="10" 34 | guidetolerance="10" 35 | inkscape:pageopacity="0" 36 | inkscape:pageshadow="2" 37 | inkscape:window-width="1600" 38 | inkscape:window-height="875" 39 | id="namedview108" 40 | showgrid="false" 41 | fit-margin-top="0" 42 | fit-margin-left="0" 43 | fit-margin-right="0" 44 | fit-margin-bottom="0" 45 | inkscape:zoom="3.3103073" 46 | inkscape:cx="1036.9331" 47 | inkscape:cy="57.60204" 48 | inkscape:window-x="0" 49 | inkscape:window-y="25" 50 | inkscape:window-maximized="0" 51 | inkscape:current-layer="svg2" /> 52 | <path 53 | d="m 502.86787,89.225694 h 13.16396" 54 | style="fill:none;stroke:#000000;stroke-width:2.63279247" 55 | id="path4" 56 | inkscape:connector-curvature="0" /> 57 | <path 58 | d="m 405.45455,89.225694 h 13.16396" 59 | style="fill:none;stroke:#000000;stroke-width:2.63279247" 60 | id="path6" 61 | inkscape:connector-curvature="0" /> 62 | <path 63 | d="M 234.32304,89.225694 H 247.487" 64 | style="fill:none;stroke:#000000;stroke-width:2.63279247" 65 | id="path8" 66 | inkscape:connector-curvature="0" /> 67 | <path 68 | d="m 193.51476,89.225694 h 13.16396" 69 | style="fill:none;stroke:#000000;stroke-width:2.63279247" 70 | id="path10" 71 | inkscape:connector-curvature="0" /> 72 | <path 73 | d="m 110.5818,89.225694 h 13.16396" 74 | style="fill:none;stroke:#000000;stroke-width:2.63279247" 75 | id="path12" 76 | inkscape:connector-curvature="0" /> 77 | <path 78 | d="m 418.61851,89.225694 q 13.16396,0 13.16396,-13.16396 v -3.290991 q 0,-13.163962 13.16396,-13.163962 h 31.59351 q 13.16396,0 13.16396,13.163962 v 3.290991 q 0,13.16396 13.16397,13.16396" 79 | style="fill:none;stroke:#000000;stroke-width:2.63279247" 80 | id="path14" 81 | inkscape:connector-curvature="0" /> 82 | <path 83 | d="M 502.86787,89.225694 H 476.53994" 84 | style="fill:none;stroke:#000000;stroke-width:2.63279247" 85 | id="path16" 86 | inkscape:connector-curvature="0" /> 87 | <path 88 | d="m 418.61851,89.225694 h 26.32792" 89 | style="fill:none;stroke:#000000;stroke-width:2.63279247" 90 | id="path18" 91 | inkscape:connector-curvature="0" /> 92 | <path 93 | d="M 405.45455,89.225694 H 392.29059" 94 | style="fill:none;stroke:#000000;stroke-width:2.63279247" 95 | id="path20" 96 | inkscape:connector-curvature="0" /> 97 | <path 98 | d="m 247.487,89.225694 h 13.16396" 99 | style="fill:none;stroke:#000000;stroke-width:2.63279247" 100 | id="path22" 101 | inkscape:connector-curvature="0" /> 102 | <path 103 | d="m 392.29059,89.225694 q -13.16397,0 -13.16397,13.163956 v 19.74595 q 0,13.16396 -13.16396,13.16396 h 0" 104 | style="fill:none;stroke:#000000;stroke-width:2.63279247" 105 | id="path24" 106 | inkscape:connector-curvature="0" /> 107 | <path 108 | d="m 260.65096,89.225694 q 13.16397,0 13.16397,13.163956 v 19.74595 q 0,13.16396 13.16396,13.16396 h 0" 109 | style="fill:none;stroke:#000000;stroke-width:2.63279247" 110 | id="path26" 111 | inkscape:connector-curvature="0" /> 112 | <path 113 | d="m 392.29059,89.225694 c -13.16397,0 -13.16397,0 -39.49189,0" 114 | style="fill:none;stroke:#000000;stroke-width:2.63279247" 115 | id="path28" 116 | inkscape:connector-curvature="0" /> 117 | <path 118 | d="m 260.65096,89.225694 c 13.16397,0 13.16397,0 39.49189,0" 119 | style="fill:none;stroke:#000000;stroke-width:2.63279247" 120 | id="path30" 121 | inkscape:connector-curvature="0" /> 122 | <path 123 | d="m 392.29059,89.225694 q -13.16397,0 -13.16397,-13.16396 V 56.31579 q 0,-13.163962 -13.16396,-13.163962 h -16.45495" 124 | style="fill:none;stroke:#000000;stroke-width:2.63279247" 125 | id="path32" 126 | inkscape:connector-curvature="0" /> 127 | <path 128 | d="m 260.65096,89.225694 q 13.16397,0 13.16397,-13.16396 V 56.31579 q 0,-13.163962 13.16396,-13.163962 h 16.45495" 129 | style="fill:none;stroke:#000000;stroke-width:2.63279247" 130 | id="path34" 131 | inkscape:connector-curvature="0" /> 132 | <path 133 | d="m 180.3508,89.225694 q 13.16396,0 13.16396,13.163956 v 3.29099 q 0,13.16397 -13.16396,13.16397 h -43.44108 q -13.16396,0 -13.16396,-13.16397 v -3.29099 q 0,-13.163956 13.16396,-13.163956" 134 | style="fill:none;stroke:#000000;stroke-width:2.63279247" 135 | id="path36" 136 | inkscape:connector-curvature="0" /> 137 | <path 138 | d="M 193.51476,89.225694 H 180.3508" 139 | style="fill:none;stroke:#000000;stroke-width:2.63279247" 140 | id="path38" 141 | inkscape:connector-curvature="0" /> 142 | <path 143 | d="m 123.74576,89.225694 h 13.16396" 144 | style="fill:none;stroke:#000000;stroke-width:2.63279247" 145 | id="path40" 146 | inkscape:connector-curvature="0" /> 147 | <desc 148 | id="desc42">Created with Raphaël 2.1.0</desc> 149 | <defs 150 | id="defs44" /> 151 | <rect 152 | x="206.67871" 153 | y="72.770744" 154 | width="27.64432" 155 | height="32.909904" 156 | r="0" 157 | rx="3.9491887" 158 | ry="3.9491887" 159 | style="fill:#dae9e5;stroke:#dae9e5;stroke-width:1.31639624" 160 | id="rect46" /> 161 | <text 162 | x="220.50089" 163 | y="89.225693" 164 | font="10px "Arial"" 165 | style="font-size:15.79675484px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial" 166 | font-size="12px" 167 | id="text48"> 168 | <tspan 169 | dy="5.9237828" 170 | id="tspan50">" "</tspan> 171 | </text> 172 | <rect 173 | x="21.562796" 174 | y="72.66703" 175 | width="89.122711" 176 | height="33.117336" 177 | r="0" 178 | rx="2.7850847" 179 | ry="3.974081" 180 | style="fill:#bada55;stroke:#bada55;stroke-width:1.10896111" 181 | id="rect52" /> 182 | <text 183 | x="47.394775" 184 | y="89.225693" 185 | font="10px "Arial"" 186 | style="font-size:15.79675484px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial" 187 | font-size="12px" 188 | id="text54"> 189 | <tspan 190 | id="tspan56"></tspan> 191 | </text> 192 | <text 193 | x="66.728333" 194 | y="94.361168" 195 | font="10px "Arial"" 196 | style="font-size:15.79675484px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial" 197 | font-size="12px" 198 | id="text3087"> 199 | <tspan 200 | id="tspan3089">boundary</tspan> 201 | </text> 202 | <rect 203 | x="515.90363" 204 | y="72.642578" 205 | width="81.317352" 206 | height="33.166233" 207 | r="0" 208 | rx="2.5411673" 209 | ry="3.979948" 210 | style="fill:#bada55;stroke:#bada55;stroke-width:1.06006885" 211 | id="rect58" /> 212 | <text 213 | x="556.56232" 214 | y="94.663254" 215 | font="10px "Arial"" 216 | style="font-size:15.79675484px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial" 217 | font-size="12px" 218 | id="text60"> 219 | <tspan 220 | id="tspan62">boundary</tspan> 221 | </text> 222 | <rect 223 | x="247.487" 224 | y="13.532914" 225 | width="157.96754" 226 | height="151.38556" 227 | r="0" 228 | rx="3.9491887" 229 | ry="3.9491887" 230 | style="fill:none;stroke:#a0a0a0;stroke-width:2.63279247;stroke-dasharray:7.89837727, 2.63279242" 231 | id="rect64" /> 232 | <text 233 | x="276.44772" 234 | y="4.9763379" 235 | font="10px "Arial"" 236 | style="font-size:13.16396236px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial" 237 | font-size="10px" 238 | id="text66"> 239 | <tspan 240 | dy="4.6073866" 241 | id="tspan68">Group #1</tspan> 242 | </text> 243 | <rect 244 | x="286.97888" 245 | y="118.8446" 246 | width="78.983772" 247 | height="32.909904" 248 | r="0" 249 | rx="3.9491887" 250 | ry="3.9491887" 251 | style="fill:#dae9e5;stroke:#dae9e5;stroke-width:1.31639624" 252 | id="rect70" /> 253 | <text 254 | x="326.47076" 255 | y="135.29956" 256 | font="10px "Arial"" 257 | style="font-size:15.79675484px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial" 258 | font-size="12px" 259 | id="text72"> 260 | <tspan 261 | dy="5.9237828" 262 | id="tspan74">"chicken"</tspan> 263 | </text> 264 | <rect 265 | x="300.14285" 266 | y="72.770744" 267 | width="52.655849" 268 | height="32.909904" 269 | r="0" 270 | rx="3.9491887" 271 | ry="3.9491887" 272 | style="fill:#dae9e5;stroke:#dae9e5;stroke-width:1.31639624" 273 | id="rect76" /> 274 | <text 275 | x="326.47076" 276 | y="89.225693" 277 | font="10px "Arial"" 278 | style="font-size:15.79675484px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial" 279 | font-size="12px" 280 | id="text78"> 281 | <tspan 282 | dy="5.9237828" 283 | id="tspan80">"cow"</tspan> 284 | </text> 285 | <rect 286 | x="303.43384" 287 | y="26.696877" 288 | width="46.073868" 289 | height="32.909904" 290 | r="0" 291 | rx="3.9491887" 292 | ry="3.9491887" 293 | style="fill:#dae9e5;stroke:#dae9e5;stroke-width:1.31639624" 294 | id="rect82" /> 295 | <text 296 | x="326.47076" 297 | y="43.151829" 298 | font="10px "Arial"" 299 | style="font-size:15.79675484px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial" 300 | font-size="12px" 301 | id="text84"> 302 | <tspan 303 | dy="5.9237828" 304 | id="tspan86">"pig"</tspan> 305 | </text> 306 | <rect 307 | x="136.90971" 308 | y="72.770744" 309 | width="43.441074" 310 | height="32.909904" 311 | r="0" 312 | rx="3.9491887" 313 | ry="3.9491887" 314 | style="fill:#bada55;stroke:#bada55;stroke-width:1.31639624" 315 | id="rect88" /> 316 | <text 317 | x="158.63025" 318 | y="89.225693" 319 | font="10px "Arial"" 320 | style="font-size:15.79675484px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial" 321 | font-size="12px" 322 | id="text90"> 323 | <tspan 324 | dy="5.9237828" 325 | id="tspan92">digit</tspan> 326 | </text> 327 | <rect 328 | x="444.94644" 329 | y="72.770744" 330 | width="31.59351" 331 | height="32.909904" 332 | r="0" 333 | rx="3.9491887" 334 | ry="3.9491887" 335 | style="fill:#dae9e5;stroke:#dae9e5;stroke-width:1.31639624" 336 | id="rect94" /> 337 | <text 338 | x="460.74319" 339 | y="89.225693" 340 | font="10px "Arial"" 341 | style="font-size:15.79675484px;font-style:normal;font-variant:normal;font-weight:normal;line-height:normal;text-anchor:middle;fill:#000000;stroke:none;font-family:Arial" 342 | font-size="12px" 343 | id="text96"> 344 | <tspan 345 | dy="5.9237828" 346 | id="tspan98">"s"</tspan> 347 | </text> 348 | <path 349 | d="M 7.8983762,89.225694 H 21.062338" 350 | style="fill:none;stroke:#000000;stroke-width:2.63279247" 351 | id="path100" 352 | inkscape:connector-curvature="0" /> 353 | <circle 354 | cx="10" 355 | cy="80.5" 356 | r="5" 357 | style="fill:#6b6659;stroke:#000000;stroke-width:2" 358 | id="circle102" 359 | sodipodi:cx="10" 360 | sodipodi:cy="80.5" 361 | sodipodi:rx="5" 362 | sodipodi:ry="5" 363 | transform="matrix(1.3163962,0,0,1.3163962,-5.2655848,-16.744199)" /> 364 | <path 365 | d="M 610.86099,88.62152 H 597.69703" 366 | style="fill:none;stroke:#000000;stroke-width:2.63279247" 367 | id="path104" 368 | inkscape:connector-curvature="0" /> 369 | <circle 370 | cx="530" 371 | cy="80.5" 372 | r="5" 373 | style="fill:#6b6659;stroke:#000000;stroke-width:2" 374 | id="circle106" 375 | sodipodi:cx="530" 376 | sodipodi:cy="80.5" 377 | sodipodi:rx="5" 378 | sodipodi:ry="5" 379 | transform="matrix(1.3163962,0,0,1.3163962,-86.82901,-17.348373)" /> 380 | </svg> 381 | -------------------------------------------------------------------------------- /img/skillsharing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/skillsharing.png -------------------------------------------------------------------------------- /img/sprites_big.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/sprites_big.png -------------------------------------------------------------------------------- /img/syntax_tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/syntax_tree.png -------------------------------------------------------------------------------- /img/transform.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/transform.png -------------------------------------------------------------------------------- /img/unicycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/unicycle.png -------------------------------------------------------------------------------- /img/weresquirrel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/img/weresquirrel.png -------------------------------------------------------------------------------- /pdf/livro.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/braziljs/eloquente-javascript/ef2425d3c0c67413d736611ecd48d5dcd143735a/pdf/livro.pdf -------------------------------------------------------------------------------- /summary.md: -------------------------------------------------------------------------------- 1 | # Sumário 2 | 3 | [Introdução](chapters/00-introducao.md) 4 | 5 | * [Valores, Tipos e Operadores](chapters/01-valores-tipos-operadores.md) - (**Parte 1: Linguagem**) 6 | * [Estrutura do Programa](chapters/02-estrutura-do-programa.md) 7 | * [Funções](chapters/03-funcoes.md) 8 | * [Estrutura de Dados: Objeto e Array](chapters/04-estruturas-de-dados.md) 9 | * [Funções de Ordem Superior](chapters/05-funcoes-de-ordem-superior.md) 10 | * [A Vida Secreta dos Objetos](chapters/06-a-vida-secreta-dos-objetos.md) 11 | * [Prática: Vida Eletrônica](chapters/07-pratica-vida-eletronica.md) 12 | * [Erros e Manipulação de Erros](chapters/08-erros-e-manipulacao-de-erros.md) 13 | * [Expressões Regulares](chapters/09-expressoes-regulares.md) 14 | * [Módulos](chapters/10-modulos.md) 15 | * [Prática: A Linguagem de Programação](chapters/11-pratica-linguagem-de-programacao.md) 16 | * [JavaScript e o Navegador](chapters/12-javascript-e-o-navegador.md) - (**Parte 2: Navegador**) 17 | * [O *Document Object Model*](chapters/13-document-object-model.md) 18 | * [Manipulando Eventos](chapters/14-manipulando-eventos.md) 19 | * [Projeto: Plataforma de Jogo](chapters/15-projeto-plataforma-de-jogo.md) 20 | * [Desenhando no Canvas](chapters/16-desenhando-no-canvas.md) 21 | * [HTTP](chapters/17-http.md) 22 | * [Formulários e Campos de Formulários](chapters/18-formularios-e-campos-de-formularios.md) 23 | * [Projeto: Um Programa de Pintura](chapters/19-projeto-um-programa-de-pintura.md) 24 | * [Node.js](chapters/20-nodejs.md) - (**Parte 3: Node.js**) 25 | * [Projeto: Website de Compartilhamento de Habilidades](chapters/21-projeto-website-de-compartilhamento-de-habilidades.md) 26 | --------------------------------------------------------------------------------