├── .gitignore ├── img ├── traduz-ai.png ├── callback-js.png ├── js-prototype.png ├── angularJS-5-exemplos.png ├── node-absolute-begginer.png └── guia-definitivo-angular.png ├── .gitmodules ├── .editorconfig ├── series ├── voce-nao-precisa-de-jquery │ ├── README.md │ ├── 00-intro.md │ ├── 01-seletores.md │ └── 02-manipulacao-dom.md └── entao-voce-quer-ser-um-programador-funcional │ ├── README.md │ ├── parte-3.md │ ├── parte-4.md │ ├── parte-2.md │ └── parte-1.md ├── angularjs ├── README.md ├── 005-entendendo-diretivas.md └── 002-aprenda-angularjs-com-5-exemplos.md ├── README.md ├── react └── 01-sua-linha-do-tempo-para-aprender-react.md ├── javascript ├── 009-uma-suave-introducao-ao-javascript-parte-1.md ├── 004-entenda-closures-no-javaScript-com-facilidade.md ├── 008-programacao-funcional-prioridade-2015.md ├── 003-escopo-de-variavel-js-e-hoisting-explicado.md ├── 010-uma-suave-introducao-ao-javascript-parte-2.md ├── 012-uma-suave-introducao-ao-javascript-parte-4.md ├── 005-prototipos-javascript-em-uma-linguagem-simples.md └── 007-um-mergulho-no-javascript-puro.md ├── MongoDB └── 001-uma-introdução-ao-mongodb.md └── nodejs └── 001-guia-para-iniciantes-absolutos-em-nodejs.md /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.sw* 3 | -------------------------------------------------------------------------------- /img/traduz-ai.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angularbrasil/artigos/HEAD/img/traduz-ai.png -------------------------------------------------------------------------------- /img/callback-js.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angularbrasil/artigos/HEAD/img/callback-js.png -------------------------------------------------------------------------------- /img/js-prototype.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angularbrasil/artigos/HEAD/img/js-prototype.png -------------------------------------------------------------------------------- /img/angularJS-5-exemplos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angularbrasil/artigos/HEAD/img/angularJS-5-exemplos.png -------------------------------------------------------------------------------- /img/node-absolute-begginer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angularbrasil/artigos/HEAD/img/node-absolute-begginer.png -------------------------------------------------------------------------------- /img/guia-definitivo-angular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angularbrasil/artigos/HEAD/img/guia-definitivo-angular.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "javascript/mdo-code-guide"] 2 | path = javascript/mdo-code-guide 3 | url = git@github.com:diegoeis/code-guide.git 4 | -------------------------------------------------------------------------------- /.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 -------------------------------------------------------------------------------- /series/voce-nao-precisa-de-jquery/README.md: -------------------------------------------------------------------------------- 1 | # Você não precisa mais de jQuery 2 | 3 | Tradução da série de artigos feito por [Ray Nicholus](https://twitter.com/raynicholus) 4 | 5 | * [Introdução](./00-intro.md) 6 | * [Seletores](./01-seletores.md) 7 | * [DOM](./02-manipulacao-dom.md) -------------------------------------------------------------------------------- /series/entao-voce-quer-ser-um-programador-funcional/README.md: -------------------------------------------------------------------------------- 1 | # Então você quer ser um Programador Funcional? 2 | 3 | Tradução da série de artigos feito por [Charles Scalfani](https://twitter.com/cscalfani) 4 | 5 | * [Parte 1](./parte-1.md) 6 | * [Parte 2](./parte-2.md) 7 | * [Parte 3](./parte-3.md) -------------------------------------------------------------------------------- /angularjs/README.md: -------------------------------------------------------------------------------- 1 | Lista 2 | 3 | - [001-guia-definitivo-para-aprender-angularjs](https://github.com/angularjsbrasil/traduz-ai/blob/master/angularjs/001-guia-definitivo-para-aprender-angularjs.md) 4 | - [002-aprenda-angularjs-com-5-exemplos](https://github.com/angularjsbrasil/traduz-ai/blob/master/angularjs/002-aprenda-angularjs-com-5-exemplos.md) 5 | - [003-use-angularjs-para-potencializar-sua-webapp](https://github.com/angularjsbrasil/traduz-ai/blob/master/angularjs/003-use-angularjs-para-potencializar-sua-webapp.md) 6 | - [004-mais-magicas-angularjs-para-turbinar-sua-webapp](https://github.com/angularjsbrasil/traduz-ai/blob/master/angularjs/004-mais-magicas-angularjs-para-turbinar-sua-webapp.md) 7 | -------------------------------------------------------------------------------- /angularjs/005-entendendo-diretivas.md: -------------------------------------------------------------------------------- 1 | # Entendendo Diretivas 2 | 3 | * **Artigo Original**: [Understanding Directives](https://github.com/angular/angular.js/wiki/Understanding-Directives) 4 | * **Tradução**: [Eric Douglas](https://github.com/ericdouglas) 5 | 6 | Este documento é uma tentativa de explicar como as Diretivas no AngularJS e suas engines compiladoras relacionadas trabalham, para que você não sinta que está se deparando com *um macarrão* a primeira vez que tentar resolver isso sozinho. 7 | 8 | ## Injetando, Compilando e Linkando funções 9 | 10 | Quando você cria uma diretiva, existem essencialmente 3 camadas de função que para você definir: 11 | 12 | ```js 13 | myApp.directive('uiJq', function InjectingFunction() { 14 | 15 | // === InjectingFunction === // 16 | // Lógica é executada 0 ou 1 vez por app 17 | // (dependendo se a diretiva é usada) 18 | // Útil para inicialização e configuração global 19 | 20 | return { 21 | compile: function CompilingFunction($templateElement, $templateAttributes) { 22 | 23 | // === CompilingFunction === // 24 | // Lógica é executada uma vez para cada instância de ui-jq no seu template original NÃO RENDERIZADO 25 | // Escopo está INDISPONÍVEL quando os modelos estão sendo cacheados. 26 | // Você PODE examinar o DOM e informação de cache sobre as variáveis ou expressões 27 | // que você vai usar, mas ainda não consegue descobrir seus valores 28 | // Angular está cacheando os templates, agora é uma boa hora de injetar novos templates do Angular 29 | // como filhos ou futuros irmãos para rodarem automaticamente. 30 | 31 | return function LinkingFunction($scope, $linkElement, $linkAttributes) { 32 | 33 | // === LinkingFunction === // 34 | // A lógica é executada uma vez para cada instância renderizada 35 | // 36 | }; 37 | 38 | } 39 | }; 40 | 41 | }); 42 | -------------------------------------------------------------------------------- /series/voce-nao-precisa-de-jquery/00-intro.md: -------------------------------------------------------------------------------- 1 | # Você não precisa de jQuery (Não mais) 2 | 3 | * **Artigo original**: [You Don't Need jQuery (anymore)](http://blog.garstasio.com/you-dont-need-jquery/why-not/) 4 | * **Tradução**: [Gabriel](https://github.com/BielRibeiro) 5 | 6 | **Muitos** desenvolvedores web dependem do jQuery. Para muitos, jQuery e Javascript parecem ser a mesma coisa. Então, por que não usá-lo? Por que parar de usá-lo? Você simplesmente não precisa dele? 7 | 8 | Com jQuery tudo fica mais fácil. Você não consegue desenvolver uma web app sólida sem ele. É muito difícil garantir que seu app funcionará corretamente em todos os browsers sem jQuery - A implementação da [Web API](http://en.wikipedia.org/wiki/Web_API) varia muito entre os browsers. 9 | Todos os bons plug-ins que eu preciso, dependem do jQuery de qualquer maneira. 10 | 11 | Usei estas desculpas acima durante a maior parte da minha carreira. E algumas delas foram, por um momento, boas desculpas. Em 2012, quando assumi a manutenção e o desenvolvimento de uma [grande biblioteca de file upload](https://github.com/FineUploader), [meu primeiro instinto foi o de reescrever tudo usando jQuery](https://github.com/FineUploader/fine-uploader/issues/326), porque eu pensei que aquilo facilitaria minha vida. A comunidade de usuários existente foi contra trazer qualquer outra dependência para a biblioteca, então fui forçado a lidar com a API nativa do browser. E quer saber? Foi mais fácil colocar o jQuery de lado do que eu imaginei. Eu não precisava do jQuery, e nem você precisa. 12 | 13 | ## A Armadilha 14 | 15 | Há algum tempo, quando entrei no mundo do desenvolvimento web, a primeira biblioteca que usei foi o jQuery. Na verdade, nunca me importei em aprender Javascript direito. Eu não tinha a menor ideia de como era a Web API, ou como mexer no DOM precisamente. O jQuery fez tudo por mim. Fui pego por esta enorme lacuna em meu conhecimento quando entrei em um projeto sem jQuery. Fui forçado a aprender desenvolvimento web direito, e nunca mais olhei para trás. 16 | 17 | Cai numa armadilha que muitos desenvolvedores web novos, casuais e amadores caem. Se primeiramente tivesse gasto meu tempo para aprender Javascript e a API do browser, teria evitado muitos problemas. A sequência correta de estudos é: 18 | 19 | 1. Aprender Javascript 20 | 2. Aprender sobre a Web API 21 | 3. Aprender jQuery (ou qualquer outro framework/biblioteca que você pode precisar nos projetos) 22 | 23 | Alguns começam com o #3 e #1, e o #2 vem somente depois (ou nunca). Se você não entende o que o jQuery na verdade está fazendo por você, haverão muitos dias frustrantes a frente, descobrindo ["vazamentos" em sua abstração](http://www.joelonsoftware.com/articles/LeakyAbstractions.html), ou no caso de você não poder usar jQuery em um projeto futuro. Esta é uma armadilha que você precisa evitar se quiser crescer efetivamente como desenvolvedor web. 24 | 25 | ## Suporte Cross-Browser 26 | 27 | Uma das razões mais usadas para valorizar o jQuery é a de arrumar a API fraca do DOM. Este é um ponto válido, mas somente se você estiver trabalhando com o IE7 ou anterior. 28 | Estamos em 2014, e o suporte a IE7 é raro. A API do DOM não é tão ruim como muitas pessoas costuman dizer. Percorrer, manipular e criar elementos é consistentemente suportado por todos os browsers modernos. 29 | 30 | A Web API como um todo é, de certa forma, bastante avançada e capaz desde o IE8. É claro, existem falhas nos browsers pré-IE10 e em algumas implementações muito antigas do Safari/Webkit, mas estas falhas podem ser solucionadas, conforme a necessidade, com bibliotecas pequenas e específicas. Em alguns casos, como o suporte cross-browser do file upload, suporte a MutationObserver ou suporte a Web Component, você precisará integrar outras bibliotecas fora o jQuery. O ponto é que jQuery não é bala de prata, e existe uma boa chance de você precisar somente de uma pequena parte do que o jQuery oferece. 31 | 32 | ## JavaScript 33 | 34 | Outra razão comum para se usar o jQuery, é a de usar atalhos para a linguagem que está por debaixo dos panos (Javascript). Esta é uma das desculpas mais esfarrapadas. É um pouco demais usar uma dependência como o jQuery simplesmente por uma maneira "melhor" de percorrer as propriedades de um objeto ou um array de elementos. Na verdade, isto é completamente desnecessário levando em conta a existência de forEach e Object.keys() (ambos disponíveis em IE9+). Ou talvez você ache que inArray() é útil? Não desde o IE9, onde [Array.prototype.indexOf](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.14) ficou disponível como parte do ES5. Existem muitos exemplos, mas eu vou guardá-los para um próximo post. 35 | 36 | ## Ok, mas eu preciso mesmo abandonar o jQuery? 37 | 38 | Mas é claro que não. Se você se sente confortável com o jQuery, e está familiar o suficiente em como o jQuery faz sua mágica, então continue usando. 39 | Esta série de posts é sobre como lhe capacitar para usar a Web API e (quando preciso) bibliotecas específicas para resolver problemas em seus web apps sem depender de grandes bibliotecas com vários propósitos que, na sua maioria, nem serão utilizados. 40 | 41 | ## Ok, mas eu devo abandonar o jQuery? 42 | 43 | Isto é com você. Esta série toda é para mostrar a Web API e o vanilla Javascript. A resposta é **não** se você precisa dar suporte a browsers muito antigos e o jQuery faz sua vida mais fácil. Porém, se você pode suportar versões de browsers mais atuais, e/ou fica feliz em escrever seu próprio código, deixe o jQuery de lado. 44 | 45 | ## Próximo Post 46 | 47 | [Selecting elements without jQuery.](http://blog.garstasio.com/you-dont-need-jquery/selectors/) (Em inglês) 48 | 49 | [Selecionando elementos sem jQuery.](01-seletores.md) (Em português) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![traduz ai](img/traduz-ai.png) 2 | 3 | > Coleção de artigos sobre desenvolvimento web traduzidos para pt-br 4 | 5 | ## Como Ajudar 6 | 7 | Além dos materiais separados para tradução, você pode contribuir através da indicação de novos artigos para as traduções e/ou com as traduções/revisões. Deixe sua contribuição **[aqui](https://github.com/ericdouglas/traduz-ai/issues)**. 8 | 9 | ## Tópicos 10 | 11 | * [AngularJS](#angularjs) (05) 12 | * [Behaviour Driven Development](#behaviour-driven-development) (01) 13 | * [Handlebars](#handlebarsjs) (01) 14 | * [JavaScript](#javascript) (12) 15 | * [MongoDB](#mongodb) (01) 16 | * [Node.js](#nodejs) (02) 17 | * [React](#react) (02) 18 | 19 | ## Séries 20 | 21 | * [Você não precisa de jQuery](series/voce-nao-precisa-de-jquery) `javascript` 22 | * [Então você quer ser um Programador Funcional?](series/entao-voce-quer-ser-um-programador-funcional) `javascript` `programação funcional` 23 | 24 | ### AngularJS 25 | 26 | 1. Guia Definitivo para Aprender AngularJS em Um Dia - [`Tradução`](angularjs/001-guia-definitivo-para-aprender-angularjs.md) [`Original`](http://toddmotto.com/ultimate-guide-to-learning-angular-js-in-one-day/) 27 | 1. Aprenda AngularJS com estes 5 exemplos práticos - [`Tradução`](angularjs/002-aprenda-angularjs-com-5-exemplos.md) [`Original`](http://tutorialzine.com/2013/08/learn-angularjs-5-examples/) 28 | 1. Use AngularJS para Potencializar sua Aplicação Web - [`Tradução`](angularjs/003-use-angularjs-para-potencializar-sua-webapp.md#use-angularjs-para-potencializar-suas-aplica%C3%A7%C3%B5es-web) [`Original`](http://www.yearofmoo.com/2012/08/use-angularjs-to-power-your-web-application.html) 29 | 1. Mais mágicas do AngularJS para turbinar sua Webapp - [`Tradução`](angularjs/004-mais-magicas-angularjs-para-turbinar-sua-webapp.md#mais-m%C3%A1gicas-do-angularjs-para-turbinar-sua-webapp) [`Original`](http://www.yearofmoo.com/2012/10/more-angularjs-magic-to-supercharge-your-webapp.html) 30 | 1. Entendendo Diretivas - [`Tradução`](angularjs/005-entendendo-diretivas.md) [`Original`](https://github.com/angular/angular.js/wiki/Understanding-Directives) 31 | 32 | ### Behaviour Driven Development 33 | 34 | 1. Behaviour Driven Development com JavaScript - [`Tradução`](bdd/001-bdd-with-js.md) [`Original`](http://gajus.com/blog/1/behaviour-driven-development-with-javascript) 35 | 36 | ### Handlebars.js 37 | 38 | 1. Aprenda Tudo sobre Handlebars.js Templating JavaScript - [`Tradução`](handlebars/001-aprenda-tudo-sobre-handlebars.md#aprenda-tudo-sobre-handlebarsjs-templating-javascript) [`Original`](http://javascriptissexy.com/handlebars-js-tutorial-learn-everything-about-handlebars-js-javascript-templating/) 39 | 40 | ### JavaScript 41 | 42 | 1. Como Aprender JavaScript Corretamente - [`Tradução`](javascript/001-como-aprender-js-corretamente.md#como-aprender-javascript-corretamente--javascriptis-sexy) [`Original`](http://javascriptissexy.com/how-to-learn-javascript-properly/) 43 | 1. Objetos JavaScript em Detalhe - [`Tradução`](javascript/002-objetos-js-em-detalhe.md#objetos-javascript-em-detalhe) [`Original`](http://javascriptissexy.com/javascript-objects-in-detail/) 44 | 1. Escopo de Variável e Hoisting no JavaScript Explicado - [`Tradução`](javascript/003-escopo-de-variavel-js-e-hoisting-explicado.md#escopo-de-vari%C3%A1vel-javascript-e-hoisting-explicado) [`Original`](http://javascriptissexy.com/javascript-variable-scope-and-hoisting-explained/) 45 | 1. Entenda Closures no JavaScript com Facilidade - [`Tradução`](javascript/004-entenda-closures-no-javaScript-com-facilidade.md#entenda-closures-no-javascript-com-facilidade) [`Original`](http://javascriptissexy.com/understand-javascript-closures-with-ease/) 46 | 1. Protótipos JavaScript em uma Linguagem Simples - [`Tradução`](javascript/005-prototipos-javascript-em-uma-linguagem-simples.md#prot%C3%B3tipos-javascript-em-uma-linguagem-simples) [`Original`](http://javascriptissexy.com/javascript-prototype-in-plain-detailed-language/) 47 | 1. Entenda Funções Callback no JavaScript e Use-as - [`Tradução`](javascript/006-entenda-callbacks-js.md) [`Original`](http://javascriptissexy.com/understand-javascript-callback-functions-and-use-them/) 48 | 1. Um Mergulho no JavaScript Puro - [`Tradução`](javascript/007-um-mergulho-no-javascript-puro.md) [`Original`](http://blog.adtile.me/2014/01/16/a-dive-into-plain-javascript/) 49 | 1. Programação Funcional Deve Ser Sua Prioridade número #1 em 2015 - [`Tradução`](javascript/008-programacao-funcional-prioridade-2015.md) [`Original`](https://medium.com/@jugoncalves/functional-programming-should-be-your-1-priority-for-2015-47dd4641d6b9) 50 | 1. Uma Suave Introdução ao JavaScript Funcional: Parte 1 - [`Tradução`](javascript/009-uma-suave-introducao-ao-javascript-parte-1.md) [`Original`](http://jrsinclair.com/articles/2016/gentle-introduction-to-functional-javascript-intro/) 51 | 1. Uma Suave Introdução ao JavaScript Funcional: Parte 2 - [`Tradução`](javascript/010-uma-suave-introducao-ao-javascript-parte-2.md) [`Original`](http://jrsinclair.com/articles/2016/gentle-introduction-to-functional-javascript-arrays/) 52 | 1. Uma Suave Introdução ao JavaScript Funcional: Parte 3 - [`Tradução`](javascript/011-uma-suave-introducao-ao-javascript-parte-3.md) [`Original`](http://jrsinclair.com/articles/2016/gentle-introduction-to-functional-javascript-functions/) 53 | 1. Uma Suave Introdução ao JavaScript Funcional: Parte 4 - [`Tradução`](javascript/012-uma-suave-introducao-ao-javascript-parte-4.md) [`Original`](http://jrsinclair.com/articles/2016/gentle-introduction-to-functional-javascript-style/) 54 | 55 | ### MongoDB 56 | 57 | 1. Uma introdução ao MongoDB - [`Tradução`](MongoDB/001-uma-introdução-ao-mongodb.md) [`Original`](https://scotch.io/tutorials/an-introduction-to-mongodb) 58 | 59 | ### Node.js 60 | 61 | 1. Guia Para Absolutos Iniciantes em Node.js - [`Tradução`](nodejs/001-guia-para-iniciantes-absolutos-em-nodejs.md) [`Original`](http://blog.modulus.io/absolute-beginners-guide-to-nodejs) 62 | 1. Guia para um dev. front-end iniciar Com Node.js, Express, Jade e MongoDB - [`Tradução`](nodejs/002-simples-guia-nodejs-jade-express-mongodb.md) [`Original`](http://cwbuecheler.com/web/tutorials/2013/node-express-mongo/) 63 | 64 | ### React 65 | 66 | 1. Sua Linha do Tempo para Aprender React - [`Tradução`](react/01-sua-linha-do-tempo-para-aprender-react.md) [`Original`](https://daveceddia.com/timeline-for-learning-react/) 67 | 1. Introdução ao React para pessoas que sabem apenas o suficiente de jQuery para sobreviver - [`Tradução`](react/02-introducao-ao-react-para-pessoas-que-sabem-apenas-jquery.md) [`Original`](http://reactfordesigners.com/labs/reactjs-introduction-for-people-who-know-just-enough-jquery-to-get-by/) 68 | 69 | ## Outros Projetos 70 | 71 | * [You Don't Know JS](https://github.com/cezaraugusto/You-Dont-Know-JS) 72 | * [Wisdom of the elePHPant](https://github.com/reginaldojunior/wisdom-of-the-elephant) 73 | -------------------------------------------------------------------------------- /series/voce-nao-precisa-de-jquery/01-seletores.md: -------------------------------------------------------------------------------- 1 | # Selecionando elementos sem jQuery 2 | 3 | * **Artigo original**: [Selecting Elements](http://blog.garstasio.com/you-dont-need-jquery/selectors/) 4 | * **Tradução**: [Gabriel](https://github.com/BielRibeiro) 5 | 6 | Quantas vezes você viu uma web app ou biblioteca que usa jQuery simplesmente para selecionar elementos? Quantas vezes você escreveu isto: ```$(#meuElemento')```? Ou isto: ```$('.meuElemento')```? Psst... Você não precisa de jQuery para selecionar elementos! Isto já é muito fácil simplesmente usando a DOM API. 7 | 8 | 1. [IDs](#ids) 9 | 2. [Classes CSS](#classes-css) 10 | 3. [Nome da Tag](#tag-name) 11 | 4. [Atributos](#atributos) 12 | 5. [Pseudo-classes](#pseudo-classes) 13 | 6. [Filhos](#filhos) 14 | 7. [Descendentes](#descendentes) 15 | 8. [Seletores de Exclusão](#seletores-exclusao) 16 | 9. [Seletores Múltiplos](#seletores-multiplos) 17 | 10. [Vê um padrão?](#padrao) 18 | 11. [Mas Eu Quero Mais](#quero-mais) 19 | 12. [Próximo](#proximo) 20 | 21 | ## Por ID 22 | 23 | *jQuery* 24 | 25 | ``` 26 | // retorna um objeto jQuery com 0-1 elementos 27 | $('#meuElemento'); 28 | ``` 29 | 30 | *DOM API* 31 | 32 | ``` 33 | // IE 5.5+ 34 | document.getElementById('meuElemento'); 35 | ``` 36 | 37 | ... ou ... 38 | 39 | ``` 40 | // IE 8+ 41 | document.querySelector('#meuElemento'); 42 | ``` 43 | 44 | Ambos os métodos retornam um único elemento. Perceba que [getElementById é mais eficiente do que usar querySelector](http://jsperf.com/getelementbyid-vs-queryselector/11). 45 | 46 | Será que o jQuery proporciona alguma vantagem aqui? Eu não vejo nenhuma. Você vê? 47 | 48 | ## Por classe CSS 49 | 50 | *jQuery* 51 | 52 | ``` 53 | // retorna um objeto jQuery com todos elementos correspondentes 54 | $('.meuElemento'); 55 | ``` 56 | 57 | *DOM API* 58 | 59 | ``` 60 | // IE 9+ 61 | document.getElementsByClassName('meuElemento'); 62 | ``` 63 | 64 | ... ou ... 65 | 66 | ``` 67 | // IE 8+ 68 | document.querySelectorAll('.meuElemento'); 69 | ``` 70 | 71 | O primeiro método retorna uma [HTMLCollection](https://developer.mozilla.org/pt-BR/docs/Web/API/HTMLCollection) e é o [mais eficiente entre as duas escolhas](http://jsperf.com/getelementsbyclassname-vs-queryselectorall/25). O método querySelectorAll sempre retorna uma [NodeList](https://developer.mozilla.org/en-US/docs/Web/API/NodeList). 72 | 73 | Novamente nada complicado. Por que se preocupar com jQuery? 74 | 75 | ## Por Nome da Tag 76 | 77 | Para selecionar todas as ```
``` de uma página, por exemplo: 78 | 79 | *jQuery* 80 | 81 | ``` 82 | $('div'); 83 | ``` 84 | 85 | *DOM API* 86 | 87 | ``` 88 | // IE 5.5+ 89 | document.getElementsByTagName('div'); 90 | ``` 91 | 92 | ... ou ... 93 | 94 | ``` 95 | // IE 8+ 96 | document.querySelectorAll('div'); 97 | ``` 98 | 99 | Como esperado, querySelectorAll (que retorna uma NodeList) é menos eficiente que o getElementsByTagName (que retorna uma HTMLCollection). 100 | 101 | ## Por Atributo 102 | 103 | Seleciona todos os elementos com o atributo "data-foo-bar" que contém o valor de "qualquerValor": 104 | 105 | *jQuery* 106 | 107 | ``` 108 | $('[data-foo-bar="qualquerValor"]'); 109 | ``` 110 | 111 | *DOM API* 112 | 113 | ``` 114 | // IE 8+ 115 | document.querySelectorAll('[data-foo-bar="qualquerValor"]'); 116 | ``` 117 | 118 | Novamente, as sintaxes da DOM API e do jQuery se mostram bastante similares. 119 | 120 | ## Por Pseudo-classe 121 | 122 | Seleciona de um form em específico, todos os campos que estão atualmente inválidos. Vamos assumir que o nosso form tem o ID "meuForm". 123 | 124 | *jQuery* 125 | 126 | ``` 127 | $('#meuForm :invalid'); 128 | ``` 129 | 130 | *DOM API* 131 | 132 | ``` 133 | // IE 10+ 134 | document.querySelectorAll('#meuForm :invalid'); 135 | ``` 136 | 137 | ## Filhos 138 | 139 | Seleciona todos os filhos de um elemento em específico, assumindo que ele possui o ID "divPai". 140 | 141 | *jQuery* 142 | 143 | ``` 144 | $('#divPai').children(); 145 | ``` 146 | 147 | *DOM API* 148 | 149 | ``` 150 | // IE 5.5+ 151 | // Observação: Este método incluirá comentários e nós de texto também. 152 | document.getElementById('divPai').childNodes; 153 | ``` 154 | 155 | ... ou ... 156 | 157 | ``` 158 | // IE 9+ (ignora comentários e nós de texto). 159 | document.getElementById('divPai').children; 160 | ``` 161 | 162 | Mas e se quiséssemos selecionar somente alguns filhos em específico? Por exemplo, somente filhos com o atributo "ng-click"? 163 | 164 | *jQuery* 165 | 166 | ``` 167 | $('#divPai').children('[ng-click]'); 168 | ``` 169 | 170 | ... ou ... 171 | 172 | ``` 173 | $('#divPai > [ng-click]'); 174 | ``` 175 | 176 | *DOM API* 177 | 178 | ``` 179 | // IE 8+ 180 | document.querySelector('#divPai > [ng-click]'); 181 | ``` 182 | 183 | ## Descendentes 184 | 185 | Seleciona todos os elementos `````` dentro da tag com ID #divPai. 186 | 187 | *jQuery* 188 | 189 | ``` 190 | $('#divPai A'); 191 | ``` 192 | 193 | *DOM API* 194 | 195 | ``` 196 | // IE 8+ 197 | document.querySelectorAll('#divPai A'); 198 | ``` 199 | 200 | ## Excluindo elementos da seleção 201 | 202 | Seleciona todas ```
```'s, exceto aquelas com a classe "ignorar". 203 | 204 | *jQuery* 205 | 206 | ``` 207 | $('DIV').not('.ignorar'); 208 | ``` 209 | 210 | ... ou ... 211 | 212 | ``` 213 | $('DIV:not(.ignorar)'); 214 | ``` 215 | 216 | *DOM API* 217 | 218 | ``` 219 | // IE 9+ 220 | document.querySelectorAll('DIV:not(.ignorar)'); 221 | ``` 222 | 223 | ## Selecionando múltiplos elementos 224 | 225 | Seleciona todos os elementos ```
```'s, ``````'s e ``` 26 | 27 | ``` 28 | 29 | O AngularJS lhe dá um grande número de [Diretivas](http://docs.angularjs.org/guide/directive) que permitem a associação de elementos HTML com os Modelos. Elas são atributos que iniciam com ng- e podem ser adicionadas a qualquer elemento. O mais importante atributo que você deve incluir em qualquer página, se você for usar o Angular, é o ng-app: 30 | 31 | ```html 32 | 33 | 34 | 35 | ``` 36 | 37 | Isso pode ser adicionado a um elemento que engloba o resto da página, como o elemento body ou uma div externa. O Angular olha para ele quando a página é carregada e automaticamente analisa todas as Diretivas que enxerga nos elementos filhos. 38 | 39 | Chega de teoria! Agora vamos ver algum código. 40 | 41 |

Menu de Navegação

42 | 43 | Para o primeiro exemplo, nós vamos construir um menu de navegação que destaca a entrada selecionada. O exemplo usa somente Diretivas do Angular, e é a mais simples aplicação possível de uso do framework. Click em no botão "Edit" para ver o código fonte. Ele está pronto para experimentação! 44 | 45 | * para testar no browser, vá para o artigo original * 46 | 47 | * Link para codepen com comentários traduzidos > [aqui](http://codepen.io/eoop/pen/FJeLu) 48 | 49 | No código acima, nós estamos usando as Diretivas Angular para definir e ler a variável ativa. Quando isso muda, causa no HTML uma atualização automática. Na terminologia Angular, esta variável é chamada um modelo. Está disponível para todas as diretivas no escopo atual, e pode ser acessada nos seus controladores (mais sobre estes no próximo exemplo). 50 | 51 | Se você já utilizou templates JavaScript antes, você é familiar com a sintaxe {{var}}. Quando o framework vê esta string, ele a substitui com o conteúdo da variável. Essa operação é repetida toda hora que a variável for modificada. 52 | 53 |

Editor Inline

54 | 55 | Para nosso segundo exemplo, nós vamos criar um simples editor inline - clicando no parágrafo vamos mostrar um tooltip (dica) com um campo de texto. Nós vamos usar um controlador que vai inicializar os modelos e declarar 2 métodos para alternar a visibilidade do tooltip. Controladores são funções regulares do JavaScript que são executadas automaticamente pelo Angular, e que são associadas com sua página usando a diretiva `ng-controller`: 56 | 57 | * para testar no browser, vá para o artigo original * 58 | 59 | * Link para codepen com comentários traduzidos > [aqui](http://codepen.io/eoop/pen/hbLKi) 60 | 61 | Quando a função controladora é executada, ela pega o objeto especial $scope como um parâmetro, adicionando propriedades ou funções para torná-los disponíveis para o View. Usando o ng-model ligado no campo de texto, faz com que o Angular atualize esta variável quando o valor do campo muda (fazendo com que re-renderizemos o parágrafo com o valor). 62 | 63 |

3. Formulário de Pedido

64 | 65 | Neste exemplo, nós vamos criar um formulário com um preço total atualizado em tempo real, usando outra das úteis propriedades do Angular - os [Filtros](http://docs.angularjs.org/guide/dev_guide.templates.filters). Filtros permitem que você modifique os modelos e possa os encadear juntos usando o caracter barra vertical `|`. No exemplo ebaixo, eu estou usando o [currency filter](http://docs.angularjs.org/api/ng.filter:currency), para tornar um número em um preço corretamente formatado, completo com um símbolo dólar e centavos. Você pode facilmente criar seus próprios filtros, como você verá no exemplo #4. 66 | 67 | * para testar no browser, vá para o artigo original * 68 | 69 | * Link para codepen com comentários traduzidos > [aqui](http://codepen.io/eoop/pen/Jnbjf) 70 | 71 | A ligação [`ng-repeat`](docs http://docs.angularjs.org/api/ng.directive:ngRepeat) é outra propriedade útil do framework. Ela permite que você faça um loop em um array de item e gere um marcador para eles. Quando um item é deletado, isso é atualizado de forma inteligente. 72 | 73 | Nota: Para uma versão completa, veja este tutorial http://tutorialzine.com/2013/05/quick-tip-convert-backbone-to-angularjs/, que foi baseado neste [outro](http://tutorialzine.com/2013/04/services-chooser-backbone-js/), escrito com Backbone.js. 74 | 75 |

4. Busca Instantânea

76 | 77 | Este exemplo vai permitir aos usuários filtrarem uma lista de itens digitando dentro de um campo de texto. Este é um outro ponto onde o Angular brilha, e é um perfeito caso de uso para escrever um filtro customizado. Para fazer isso entretanto, nós primeiro temos que transformar nossa aplicação em um módulo. 78 | 79 | Módulos são uma forma de se organizar aplicações JavaScript dentro de componentes auto-suficientes que podem ser combinados de formas novas e interessantes. O Angular depende desta técnica para o isolamento do código e requer que sua aplicação siga isso antes de criar um filtro. Há apenas duas coisas que você precisa fazer para tornar sua aplicação um módulo: 80 | 81 | 1. Usar a função `angular.module("name", [])` chamada em seu JS. Isso irá instanciar e retornar um novo módulo; 82 | 83 | 2. Passar o nome do módulo como valor da diretiva `ng-app`. 84 | 85 | Criando um filtro que é tão simples com chamar o método `filter()` no objeto retornado pelo módulo `angular.module ("name", [])` 86 | 87 | * Para testar no browser, vá para o artigo original * 88 | 89 | * Link para codepen com comentários traduzidos > [aqui](http://codepen.io/eoop/pen/sBkte) 90 | 91 | Filtros seguem a filosofia do AngularJS - cada pedaço de código que você escreve deve ser auto-suficiente, testável e reutilizável. Você pode usar este filtro em todas as suas Views e até mesmo combiná-lo com outros através do encadeamento. 92 | 93 |

5. Grade Alternável

94 | 95 | Outra interação UI (user interface) popular é mudar entre modelos diferentes de layout (grid ou lista) *grid = grade* com o click de um botão. Isto é muito fácil de se fazer no Angular. Em adição, eu vou introduzir outro importante conceito - Services. Eles são objetos que podem ser usados em sua aplicação para se comunicar com o servidor, uma API ou outra fonte de dados. No nosso caso, nós vamos escrever um serviço que comunica com [API do Instagram](http://instagram.com/developer/) e retorna um array com as mais populares fotos do momento. 96 | 97 | Note que para este código funcionar, teremos que incluir um arquivo adicional Angular.js na página: 98 | 99 | ```html 100 | 101 | 102 | 103 | ``` 104 | 105 | Isso inclui o módulo [ngResource](http://docs.angularjs.org/api/ngResource.$resource) para um simples trabalho com API's AJAX (o módulo é exposto como a variável `$resource` no código). Este arquivo é automaticamente incluso no editor abaixo. 106 | 107 | * para testar no browser, vá para o artigo original * 108 | 109 | * Link para codepen com comentários traduzidos > [aqui](http://codepen.io/eoop/pen/aJmvg) 110 | 111 | Services são totalmente auto-suficientes, tornando possível escrever diferentes implementações sem que isso afete o resto do seu código. Por exemplo, durante o teste, você pode preferir retornar um array hard-coded (com código inserido diretamente no seu programa) para acelerar seus testes. 112 | 113 |

Leitura Adicional

114 | 115 | Se você tiver alcançado este ponto, você já compreendeu o básico do desenvolvimento com AngularJS. Entretanto, há muito mais a se aprender se você quiser se tornar um profissional. Aqui temos uma lista de recursos que vão ajudá-lo nesta questão: 116 | 117 | * [AngularJS Home Page](http://angularjs.org/) 118 | * [AngularJS Guide](http://docs.angularjs.org/guide/overview) 119 | * [Tutorial Oficial do AngularJS](http://docs.angularjs.org/tutorial) 120 | * [Lista de muitos e muitos recursos, vídeos e tutoriais](https://github.com/jmcunningham/AngularJS-Learning) 121 | 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /series/entao-voce-quer-ser-um-programador-funcional/parte-4.md: -------------------------------------------------------------------------------- 1 | # Então você quer ser um Programador Funcional? (Parte 4) 2 | 3 | * **Artigo original**: [So You Want to be a Functional Programmer (Part 4)](https://medium.com/@cscalfani/so-you-want-to-be-a-functional-programmer-part-4-18fbe3ea9e49#.ybnyvxuyi) 4 | * **Tradução**: [Gabriel](https://github.com/gabriel-ribeiro-ir) 5 | 6 | Dar o primeiro passo para entender os conceitos de Programação Funcional é o mais importante e algumas vezes o passo mais díficil. Mas isto não tem de ser assim. Não com a perspectiva correta. 7 | 8 | Parte anterior: 9 | 10 | [Parte 3](parte-3.md) (em português) 11 | [Parte 3](https://medium.com/@cscalfani/so-you-want-to-be-a-functional-programmer-part-3-1b0fd14eb1a7#.zffq7cklj) (em inglês) 12 | 13 | ### Currying 14 | Se você se lembra da [Parte 3](parte-3.md), a razão pela qual tivemos problemas compondo **mult5** e **add** (in) é porque **mult5** recebia 1 parâmetro e **add** recebia 2. 15 | 16 | Podemos resolver este problema facilmente restringindo todas as funções a receber somente 1 parâmetro. 17 | 18 | Acredite em mim, isto não é tão ruim quanto parece. 19 | 20 | Simplesmente escrevemos uma função add que usa 2 parâmetros mas recebe somente 1 por vez. **Curried functions** nos permite fazer isto. 21 | 22 | > Uma Curried function é uma função que recebe somente 1 parâmetro por vez. 23 | 24 | Isto vai permitir que passemos para **add** seu primeiro parâmetro antes de compormos ela com **mult5**. 25 | Então quando **mult5AfterAdd10** é chamada, **add** receberá seu segundo parâmetro. 26 | 27 | Em Javascript, podemos realizar isto reescrevendo *add**: 28 | 29 | `var add = x => y => x + y` 30 | 31 | Esta versão de *add** é uma função que recebe um parâmetro agora e então recebe outro depois. 32 | 33 | Em detalhes, a função *add** recebe um único parâmetro **x**, e retorna uma **função** que recebe somente 1 parâmetro **y**, que acabará retornando o **resultado da adição entre x e y**. 34 | 35 | Agora podemos usar esta versão de **add** para construir uma versão funcional de **mult5AfterAdd10**: 36 | 37 | ``` 38 | var compose = (f, g) => x => f(g(x)); 39 | var mult5AfterAdd10 = compose(mult5, add(10)); 40 | ``` 41 | 42 | A função *compose* recebe 2 parâmetros, **f** e **g**. Então retorna uma função que recebe 1 parâmetro, **x**, que quando chamada aplicará **f** após **g** de **x**. 43 | 44 | Então, o que fizemos exatamente? Bem, nós convertemos nossa antiga função **add** simples em uma versão *curried*. isto torna **add** mais flexível agora que o primeiro parâmetro, 10, pode ser passado na frente e o parâmetro final será passado quando **mult5AfterAdd10** é chamada. 45 | 46 | Neste ponto, você deve estar pensando em como reescrever a função add em Elm. Acontece que você não precisa. Em Elm e outras linguagens funcionais, toda função é automaticamente *curried*. 47 | 48 | Então a função **add** continua a mesma: 49 | 50 | ``` 51 | add x y = 52 | x + y 53 | ``` 54 | 55 | É assim que **mult5AfterAdd10** deveria ter sido escrito na [Parte 3](https://medium.com/@cscalfani/so-you-want-to-be-a-functional-programmer-part-3-1b0fd14eb1a7#.zffq7cklj): 56 | 57 | ``` 58 | mult5AfterAdd10 = 59 | (mult5 << add 10) 60 | ``` 61 | 62 | Sintaticamente falando, Elm supera linguagens imperativas como Javascript porque é otimizada para coisas funcionais como currying e composição. 63 | 64 | ### Currying e Refatoração 65 | 66 | Outro ponto em que Currying brilha é durante a refatoração, quando criamos uma versão genérica de uma função com um monte de parâmetros e então a usamos para criar versões específicas com menos parâmetros. 67 | 68 | Por exemplo, quando temos as seguintes funções que colocam colchetes e colchetes duplos ao redor de strings: 69 | 70 | ``` 71 | bracket str = 72 | "{" ++ str ++ "}" 73 | 74 | doubleBracket str = 75 | "{{" ++ str ++ "}}" 76 | ``` 77 | 78 | Aqui está como utilizamos: 79 | 80 | ``` 81 | bracketedJoe = 82 | bracket "Joe" 83 | 84 | doubleBracketedJoe = 85 | doubleBracket "Joe" 86 | ``` 87 | 88 | Nós podemos generalizar **bracket** e **doubleBracket**: 89 | 90 | ``` 91 | generalBracket prefix str suffix = 92 | prefix ++ str ++ suffix 93 | ``` 94 | 95 | Mas agora toda vez que usarmos **generalBracket** temos que passar os colchetes: 96 | 97 | ``` 98 | bracketedJoe = 99 | generalBracket "{" "Joe" "}" 100 | 101 | doubleBracketedJoe = 102 | generalBracket "{{" "Joe" "}}" 103 | ``` 104 | 105 | O que realmente queremos é o melhor dos dois mundos. 106 | 107 | Se nós reordenarmos os parâmetros de **generalBracket**, podemos criar **bracket** e **doubleBracket** aproveitando o fato de que as funções são curried: 108 | 109 | ``` 110 | generalBracket prefix suffix str = 111 | prefix ++ str ++ suffix 112 | 113 | bracket = 114 | generalBracket "{" "}" 115 | 116 | doubleBracket = 117 | generalBracket "{{" "}}" 118 | ``` 119 | 120 | Note que colocando os parâmetros que eram mais suscetíveis de serem estáticos, por exemplo **prefix** e **suffix**, e colocando os parâmetros mais propensos a mudar por último, por exemplo **str**, podemos facilmente criar versões especializadas de **generalBracket**. 121 | 122 | > A ordem dos parâmetros é importante para aproveitar completamente o currying. 123 | 124 | Note também que **bracket** e **doubleBracket** são escritos em notação point-free, por exemplo o parâmetro **str** é implícito. Ambos **bracket** e **doubleBracket** são funções esperando pelo seu parâmetro final. 125 | 126 | Agora podemos usá-las como antes: 127 | 128 | ``` 129 | bracketedJoe = 130 | bracket "Joe" 131 | 132 | doubleBracketedJoe = 133 | doubleBracket "Joe" 134 | ``` 135 | 136 | Mas desta vez estamos usando uma função *curried* genérica, **generalBracket**. 137 | 138 | ### Funções funcionais comuns 139 | 140 | Vamos dar uma olhada em 3 funções comuns que são usadas em linguagens funcionais. 141 | 142 | Mas primeiro, vejamos o seguinte código Javascript: 143 | 144 | ``` 145 | for (var i = 0; i < something.length; ++i) { 146 | // do stuff 147 | } 148 | ``` 149 | 150 | Existe um problema com este código. Não é um bug. O problema é que este código é um boilerplate, isto é, código que é escrito de novo e de novo. 151 | 152 | Se você programa em Linguagens imperativas como, Java, C#, Javascript, PHP, Python, etc., você se verá escrevendo este boilerplate mais que qualquer um. 153 | 154 | É isso que está errado nele. 155 | 156 | Então vamos matá-lo. Vamos colocá-lo em uma função (ou em um par de funções) e nunca mais escrever um loop for novamente. Bem, quase nunca. Pelo menos até mudarmos para uma linguagem funcional. 157 | 158 | Vamos começar modificando um Array chamado **things**: 159 | 160 | ``` 161 | var things = [1, 2, 3, 4]; 162 | for (var i = 0; i < things.length; ++i) { 163 | things[i] = things[i] * 10; // MUTATION ALERT !!!! 164 | } 165 | console.log(things); // [10, 20, 30, 40] 166 | ``` 167 | 168 | UGH!! Mutabilidade! 169 | 170 | Vamos tentar novamente. Desta vez não vamos mudar **things**: 171 | 172 | ``` 173 | var things = [1, 2, 3, 4]; 174 | var newThings = []; 175 | for (var i = 0; i < things.length; ++i) { 176 | newThings[i] = things[i] * 10; 177 | } 178 | console.log(newThings); // [10, 20, 30, 40] 179 | ``` 180 | 181 | Beleza, não modificamos **things** mas tecnicamente nós mudamos **newThings**. Por enquanto, deixaremos isto passar, afinal de contas estamos em Javascript. Uma vez que mudarmos para uma Linguagem Funcional, nós não vamos conseguir modificar. 182 | 183 | O objetivo aqui é entender como estas funções funcionam e nos ajudam a "reduzir barulho" em nosso código. 184 | 185 | Vamos pegar este código e colocá-lo em uma função. Nós vamos chamar nossa primeira função comum de **map**, agora que ela mapeia cada valor no array antigo para novos valores no novo array. 186 | 187 | ``` 188 | var map = (f, array) => { 189 | var newArray = []; 190 | for (var i = 0; i < array.length; ++i) { 191 | newArray[i] = f(array[i]); 192 | } 193 | return newArray; 194 | }; 195 | ``` 196 | 197 | Perceba que passamos como parâmetro uma função **f**, para que nosso **map** possa fazer qualquer coisa que quisermos com cada item do **array**. 198 | 199 | Agora podemos reescrever nosso código anterior para usar o **map**: 200 | 201 | ``` 202 | var things = [1, 2, 3, 4]; 203 | var newThings = map(v => v * 10, things); 204 | ``` 205 | 206 | Olha mãe. Sem loops for. E muito mais fácil de ler e portanto, descobrir sobre o que é. 207 | 208 | Bem, tecnicamente existem loops for na função **map**. Mas pelo menos nós não temos mais que escrever aquele código boilerplate. 209 | 210 | Agora vamos escrever outra função comum para **filtrar** coisas de um array: 211 | 212 | ``` 213 | var filter = (pred, array) => { 214 | var newArray = []; 215 | for (var i = 0; i < array.length; ++i) { 216 | if (pred(array[i])) 217 | newArray[newArray.length] = array[i]; 218 | } 219 | return newArray; 220 | }; 221 | ``` 222 | 223 | Note como a função pressuposta **pred** retorna TRUE se mantivermos o item ou FALSE se o removermos. 224 | 225 | Aqui está como usamos **filter** para filtrar números ímpares: 226 | 227 | ``` 228 | var isOdd = x => x % 2 !== 0; 229 | var numbers = [1, 2, 3, 4, 5]; 230 | var oddNumbers = filter(isOdd, numbers); 231 | console.log(oddNumbers); // [1, 3, 5] 232 | ``` 233 | 234 | Utilizar nossa nova função **filter** é tão mais simples que codificar na mão com um loop for. 235 | 236 | A função comum final é chamada de **reduce**. Tipicamente é usada para receber uma lista e reduzí-la a um único valor mas ela pode na verdade fazer muito mais. 237 | 238 | Esta função é comumente chamada de **fold** em Linguagens Funcionais. 239 | 240 | ``` 241 | var reduce = (f, start, array) => { 242 | var acc = start; 243 | for (var i = 0; i < array.length; ++i) 244 | acc = f(array[i], acc); // f() takes 2 parameters 245 | return acc; 246 | }); 247 | ``` 248 | 249 | A função **reduce** recebe uma função de redução, **f**, um valor **start** inicial e um **array**. 250 | 251 | Perceba que a função de redução, **f**, aceita 2 parâmetros, o item atual do **array**, e o acumulador, **acc**. A função vai usar estes parâmetros para produzir um novo acumulador a cada interação. O acumulador da interação final é retornado. 252 | 253 | Um exemplo vai nos ajudar a entender como isto funciona: 254 | 255 | ``` 256 | var add = (x, y) => x + y; 257 | var values = [1, 2, 3, 4, 5]; 258 | var sumOfValues = reduce(add, 0, values); 259 | console.log(sumOfValues); // 15 260 | ``` 261 | 262 | Veja que a função **add** soma seus 2 parâmetros recebidos. Nossa função **reduce** espera uma função que recebe 2 parâmetros então elas funcionarão bem juntas. 263 | 264 | Começamos com um valor **start** de zero e passamos nosso array, **values**, para ser somado. Dentro da função **reduce**, a soma é acumulada à medida que intera sobre os valores. O valor final acumulado é retornado como **sumOfValues**. 265 | 266 | Cada uma destas funções, **map**, **filter** e **reduce** nos permite fazer operações de manipulação comuns em arrays sem precisar escrever boilerplate de loops for. 267 | 268 | Mas em Linguagens Funcionais, elas são ainda mais úteis uma vez que não existem construtores de loop, somente recursão. Funções de iteração não são somente extremamente úteis. Elas são necessárias. 269 | 270 | ### Meu cérebro!!! 271 | 272 | Por enquanto chega. 273 | 274 | Nas próximas partes deste artigo, eu vou falar sobre Integridade referencial, ordem de execução, tipos e mais. 275 | 276 | A seguir: 277 | 278 | [Parte 5](https://medium.com/@cscalfani/so-you-want-to-be-a-functional-programmer-part-5-c70adc9cf56a#.nyj0fmsk3) (em inglês) 279 | -------------------------------------------------------------------------------- /series/entao-voce-quer-ser-um-programador-funcional/parte-2.md: -------------------------------------------------------------------------------- 1 | # Então você quer ser um Programador Funcional? (Parte 2) 2 | 3 | * **Artigo original**: [So You Want to be a Functional Programmer (Part 2)](https://medium.com/@cscalfani/so-you-want-to-be-a-functional-programmer-part-2-7005682cec4a#.q2xydwfne) 4 | * **Tradução**: [Gabriel](https://github.com/gabriel-ribeiro-ir) 5 | 6 | Dar o primeiro passo para entender os conceitos de Programação Funcional é o mais importante e algumas vezes o passo mais díficil. Mas isto não tem de ser assim. Não com a perspectiva correta. 7 | 8 | Parte anterior: 9 | 10 | [Parte 1](parte-1.md) (em português) 11 | [Parte 1](https://medium.com/@cscalfani/so-you-want-to-be-a-functional-programmer-part-1-1f15e387e536#.es7crd8y1) (em inglês) 12 | 13 | ### Lembrete Amigável 14 | 15 | Por favor leia o código lentamente. Tenha certeza de ter entendido antes de seguir em frente. Cada seção é baseada na anterior. 16 | 17 | Se você se apressar, pode perder alguma coisa que será importante mais tarde. 18 | 19 | ### Refatoração 20 | 21 | Vamos pensar em refatoração por um minuto. Aqui vai um pouco de código Javascript: 22 | 23 |
 24 | 	
 25 | function validateSsn(ssn) {
 26 |     if (/^\d{3}-\d{2}-\d{4}$/.exec(ssn))
 27 |         console.log('Valid SSN');
 28 |     else
 29 |         console.log('Invalid SSN');
 30 | }
 31 | function validatePhone(phone) {
 32 |     if (/^\(\d{3}\)\d{3}-\d{4}$/.exec(phone))
 33 |         console.log('Valid Phone Number');
 34 |     else
 35 |         console.log('Invalid Phone Number');
 36 | }
 37 | 	
 38 | 
39 | 40 | Todos nós já escrevemos código como este ao longo do tempo, começamos a reconhecer que estas duas funções são praticamente iguais e diferenciam-se somente por algumas coisas (mostradas em **negrito**). 41 | 42 | Ao invés de copiar **validadeSsn**, colar e editar para criar **validatePhone**, nós deveríamos criar uma única função e parametrizar as coisas que nós editamos depois de colar. 43 | 44 | Neste exemplo, nós passaríamos como parâmetro o **value**, a **regular expression** e a **mensagem** (pelo menos a última parte da mensagem). 45 | 46 | O código refatorado: 47 | 48 |
 49 | 
 50 | function validateValue(value, regex, type) {
 51 |     if (regex.exec(value))
 52 |         console.log('Invalid ' + type);
 53 |     else
 54 |         console.log('Valid ' + type);
 55 | }
 56 | 
 57 | 
58 | 59 | Os parâmetros **ssn** e **phone** no código antigo, agora são representados pelo **value**. 60 | 61 | As expressões regulares **/^\d{3}-\d{2}-\d{4}$/** e **/^\(\d{3}\)\d{3}-\d{4}$/** são representadas pelo **regex**. 62 | 63 | E por último, a última parte da mensagem **SSN** e **'Phone Number'** são representados pelo **type**. 64 | 65 | Ter uma função é muito melhor do que ter duas funções. Ou pior, três, quatro ou dez funções. Isto mantém seu código limpo e fácil de manter. 66 | 67 | Por exemplo, se houver um bug, você precisa arrumar somente em um lugar versus procurar por todo o codebase para para achar o lugar onde esta função PODE ter sido posta e modificada. 68 | 69 | Mas o quê acontece quando você tem a seguinte situação: 70 | 71 |
 72 | 
 73 | function validateAddress(address) {
 74 |     if (parseAddress(address))
 75 |         console.log('Valid Address');
 76 |     else
 77 |         console.log('Invalid Address');
 78 | }
 79 | function validateName(name) {
 80 |     if (parseFullName(name))
 81 |         console.log('Valid Name');
 82 |     else
 83 |         console.log('Invalid Name');
 84 | }
 85 | 
 86 | 
87 | 88 | Aqui **parseAddress** e **parseFullName** são funções que recebem uma **string** e retornam **true** se ela for analisada. 89 | 90 | Como refatoramos isto? 91 | 92 | Bem, nós podemos usar **value** para **address** e **name**, e **type** para **'Address'** e **'Name'** como fizemos antes mas existe uma função onde nossa expressão regular costumava estar. 93 | 94 | Se nós somente pudéssemos passar uma função como parâmetro... 95 | 96 | ### High-Order Functions 97 | 98 | Muitas linguagens não suportam passar funções como parâmetros. Algumas sim mas elas não facilitam. 99 | 100 | > Em Programação Funcional, uma função é um cidadão de primeira classe da linguagem. Em outras palavras, uma função é somente outro valor. 101 | 102 | Uma vez que função são somente valores, podemos passá-las como parâmetros. 103 | 104 | Mesmo que a Javascript não seja uma Linguagem Puramente Funcional, você pode fazer algumas operações funcionais com ela. Então aqui estão as últimas duas funções refatoradas em uma única função passando a **função de parse** como parâmetro chamado **parseFunc**: 105 | 106 |
107 | 
108 | function validateValueWithFunc(value, parseFunc, type) {
109 |     if (parseFunc(value))
110 |         console.log('Invalid ' + type);
111 |     else
112 |         console.log('Valid ' + type);
113 | }
114 | 
115 | 
116 | 117 | Nossa nova função é chamada de **High-order Function**. 118 | 119 | > High-order Functions também recebe funções como parâmetros, retorna funções ou ambas. 120 | 121 | Agora podemos chamar nossa high-order function para as 4 funções anteriores (isto funciona na Javascript porque **Regex.exe** retorna um valor verdadeiro quando uma combinação é encontrada): 122 | 123 | ``` 124 | validateValueWithFunc('123-45-6789', /^\d{3}-\d{2}-\d{4}$/.exec, 'SSN'); 125 | validateValueWithFunc('(123)456-7890', /^\(\d{3}\)\d{3}-\d{4}$/.exec, 'Phone'); 126 | validateValueWithFunc('123 Main St.', parseAddress, 'Address'); 127 | validateValueWithFunc('Joe Mama', parseName, 'Name'); 128 | ``` 129 | 130 | Isto é muito melhor do que ter 4 funções identicas. 131 | 132 | Mas note as expressões regulares. Elas são um pouco verbosas. Vamos limpar nosso código refatorando-o: 133 | 134 |
135 | 
136 | var parseSsn = /^\d{3}-\d{2}-\d{4}$/.exec;
137 | var parsePhone = /^\(\d{3}\)\d{3}-\d{4}$/.exec;
138 | validateValueWithFunc('123-45-6789', parseSsn, 'SSN');
139 | validateValueWithFunc('(123)456-7890', parsePhone, 'Phone');
140 | validateValueWithFunc('123 Main St.', parseAddress, 'Address');
141 | validateValueWithFunc('Joe Mama', parseName, 'Name');
142 | 
143 | 
144 | 145 | Assim está melhor. Agora quando queremos analisar um número de telefone, não precisamos copiar e colar a expressão regular. 146 | 147 | Mas imagine que temos mais expressões regulares para analisar, não somente **parseSsn** e **parsePhone**. Cada vez que criamos um analisador de expressão regular, temos que lembrar de adicionar o **.exec** no final. E acredite, isto é fácil de esquecer. 148 | 149 | Podemos nos proteger disso criando uma high-order function que retorna a função **exec**: 150 | 151 |
152 | 
153 | function makeRegexParser(regex) {
154 |     return regex.exec;
155 | }
156 | var parseSsn = makeRegexParser(/^\d{3}-\d{2}-\d{4}$/);
157 | var parsePhone = makeRegexParser(/^\(\d{3}\)\d{3}-\d{4}$/);
158 | validateValueWithFunc('123-45-6789', parseSsn, 'SSN');
159 | validateValueWithFunc('(123)456-7890', parsePhone, 'Phone');
160 | validateValueWithFunc('123 Main St.', parseAddress, 'Address');
161 | validateValueWithFunc('Joe Mama', parseName, 'Name');
162 | 
163 | 
164 | 165 | Aqui, **makeRegexParser** recebe uma expressão regular e retorna a função **exec**, que recebe uma string. **validateValueWithFunc** passará a string, **value**, para a função de parse, isto é **exec**. 166 | 167 | **parseSsn** e **parsePhone** são efetivamente as mesmas de antes, a função **exec** da expressão regular. 168 | 169 | Isto é uma ligeira melhoria, mas é mostrada aqui para dar um exemplo de high-order function que retorna uma função. 170 | 171 | Contudo, você pode imaginar os benefícios de fazer esta mudança caso **makeRegexParser** fosse mais complexa. 172 | 173 | Aqui está um outro exemplo de high-order function que retorna uma função: 174 | 175 | ``` 176 | function makeAdder(constantValue) { 177 | return function adder(value) { 178 | return constantValue + value; 179 | }; 180 | } 181 | ``` 182 | 183 | Aqui temos **makeAdder** que recebe **constantValue** e retorna **adder**, uma função que irá adicionar essa constante para qualquer valor que for passado. 184 | 185 | Aqui está como pode ser usada: 186 | 187 | ``` 188 | var add10 = makeAdder(10); 189 | console.log(add10(20)); // prints 30 190 | console.log(add10(30)); // prints 40 191 | console.log(add10(40)); // prints 50 192 | ``` 193 | 194 | Nós criamos uma função, **add10**, passando a constante **10** para **makeAdder** que retorna a função que irá somar **10** para tudo. 195 | 196 | Perceba que a função **adder** tem acesso a **constantValue** mesmo depois de **makeAdder** retorna. Isto é porque **constantValue** estava em seu escopo quando **adder** foi criado. 197 | 198 | Este comportamento é bastante importante porque sem ele, funções que retornam funções não seriam muito úteis. Então é importante entendermos como elas funcionam e como este comportamento é chamado. 199 | 200 | Este comportamento é chamado de **Closure**. 201 | 202 | ### Closures 203 | 204 | Aqui está um exemplo planejado para mostrar o uso de closures: 205 | 206 |
207 | 
208 | function grandParent(g1, g2) {
209 |     var g3 = 3;
210 |     return function parent(p1, p2) {
211 |         var p3 = 33;
212 |         return function child(c1, c2) {
213 |             var c3 = 333;
214 |             return g1 + g2 + g3 + p1 + p2 + p3 + c1 + c2 + c3;
215 |         };
216 |     };
217 | }
218 | 
219 | 
220 | 221 | Neste exemplo, **child** tem acesso as suas variáveis, as variáveis de **parent** e **grandParent**. 222 | 223 | A **parent** tem acesso as suas variáveis e as da **grandParent**. 224 | 225 | A **grandParent** tem acesso somente as suas variáveis. 226 | 227 | (Veja a pirâmide acima para esclarecimento.) 228 | 229 | Aqui está um exemplo de seu uso: 230 | 231 | ``` 232 | var parentFunc = grandParent(1, 2); // returns parent() 233 | var childFunc = parentFunc(11, 22); // returns child() 234 | console.log(childFunc(111, 222)); // prints 738 235 | // 1 + 2 + 3 + 11 + 22 + 33 + 111 + 222 + 333 == 738 236 | ``` 237 | 238 | Aqui, **parentFunc** mantém o escopo de **parent** vivo visto que **grandParent** retorna **parent**. 239 | 240 | Do mesmo modo, **childFunc** mantém o escopo de **child** vivo visto que **parentFunc** que é apenas **parent**, retorna **child**. 241 | 242 | Quando uma função é criada, todas as variáveis em seu escopo **em tempo de criação** são acessíveis a ela pelo tempo de vida da função. Uma função existe enquanto houver uma referência à ela. Por exemplo, o escopo de **child** existe enquanto **childFunc** referenciá-lo. 243 | 244 | > Uma closure é um escopo de uma função que é mantido vivo por uma referência àquela função. 245 | 246 | Note que na Javascript, closures são problemáticas visto que as variáveis são mutáveis, isto é, elas podem mudar de valor do tempo em que elas foram "enclausuradas" para o tempo que a função retornada é chamada. 247 | 248 | Agradecidamente, variáveis em Linguagens Funcionais são imutáveis, eliminando esta fonte comum de bugs e confusão. 249 | 250 | ### Meu cérebro!!! 251 | 252 | Por enquanto chega. 253 | 254 | Nas próximas partes deste artigo, eu vou falar sobre Functional Composition, Currying, funções funcionais comuns (ex: map, filter, fold etc.), e mais. 255 | 256 | A seguir: 257 | 258 | [Parte 3](parte-3.md) (em português) 259 | [Parte 3](https://medium.com/@cscalfani/so-you-want-to-be-a-functional-programmer-part-3-1b0fd14eb1a7#.zffq7cklj) (em inglês) 260 | -------------------------------------------------------------------------------- /javascript/008-programacao-funcional-prioridade-2015.md: -------------------------------------------------------------------------------- 1 | # Programação Funcional Deve Ser Sua Prioridade número #1 em 2015 2 | ### - OOP não pode mais nos salvar do *Cloud Monster* 3 | 4 | * **Artigo Original**: [Functional Programming should be your #1 priority for 2015](https://medium.com/@jugoncalves/functional-programming-should-be-your-1-priority-for-2015-47dd4641d6b9) 5 | * **Tradução**: [Eric Douglas](https://github.com/ericdouglas) e [Diogo Beato](https://github.com/diogobeato) 6 | 7 | Você provavelmente já ouviu expressões como "Clojure", "Scala", "Erlang", ou mesmo "Java agora tem *lambdas*". E você deve saber que isso tem alguma coisa a ver com "Programação Funcional". Se você participa de qualquer comunidade de programação, esse assunto provavelmente apareceu alguma vez. 8 | 9 | Se você já buscou por "Functional Programming" (ou Programação Funcional), viu que não existe nada de novo. A segunda linguagem criada já utilizava isso, apareceu por volta da década de 50, nominada *Lisp*. Por que, então, as pessoas estão empolgadas com isso apenas agora? Quase 60 anos depois!? 10 | 11 | ## No início, os computadores eram realmente lentos 12 | 13 | Acredite nisso ou não, computadores eram muuuuito mais lentos que o DOM. Não, sério. E naquele tempo, existiam duas mentalidades principais em termos de arquitetura e implementação de linguagens de programação: 14 | 15 | 1. Iniciar pela Arquitetura Von Neumann e adicionar abstração. 16 | 1. Iniciar pela Matemática e remover abstração. 17 | 18 | Os computadores não tinham tanto poder de processamento para lidar com abstrações por todo o caminho e executar os programas funcionais. Então, Lisp acabou sendo mortalmente lenta, portanto, não adequada para o trabalho. Foi quando a programação imperativa começou sua dominação, especialmente com a ascenção do *C*. 19 | 20 | ### Mas os computadores melhoraram muito 21 | 22 | Agora é virtualmente possível rodar a maioria das aplicações sem se preocupar muito sobre em qual linguagem foi escrita. Finalmente, linguagens funcionais tiveram sua segunda chance. 23 | 24 | ## Programação Funcional 50.5 25 | 26 | Isso não é uma introdução a *FP* (*Functional Programming*). No fim dessa seção, você deverá ter uma ideia de o que *FP* é e como começar sua jornada. 27 | 28 | Você pode entender Programação Funcional por programação com funções, que é, de fato, muito mais literal do que você pode imaginar agora. Você vai criar funções em termos de outras funções e compor funções (Você se lembra `f ∘ g` da escola? Isso vai ser útil agora). 29 | 30 | Aqui temos uma (não-exaustiva) lista de características da FP: 31 | 32 | 1. First-Class Functions (Funções de Primeira Classe) 33 | 1. High-Order Functions (Funções de Alta Ordem) 34 | 1. Pure Functions (Funções Puras) 35 | 1. Closures 36 | 1. Immutable State (Imutabilidade de Estado) 37 | 38 | Você não deve se preocupar com nomes *sofisticados* agora: apenas entenda o que eles significam. 39 | 40 | **First-Class Functions**, ou *Funções de Primeira Classe*, significa que você vai armazenar funções dentro de uma variável. Acredito que você já fez algo parecido com isso em JavaScript: 41 | 42 | ```js 43 | var add = function(a, b){ 44 | return a + b 45 | } 46 | ``` 47 | 48 | Você está apenas armazenando uma função anônima que recebe `a` e `b`, e retorna `a + b`, dentro de uma variável denominada `add`. 49 | 50 | **High-Order Functions**, ou *Funções de Alta Ordem*, significa que funções podem retornar funções ou receber funções como parâmetro. 51 | 52 | Novamente, em JavaScript: 53 | 54 | ```js 55 | document.querySelector('#button') 56 | .addEventListener('click', function(){ 57 | alert('yay, i got clicked') 58 | }) 59 | ``` 60 | 61 | ou 62 | 63 | ```js 64 | var add = function(a){ 65 | return function(b){ 66 | return a + b 67 | } 68 | } 69 | 70 | var add2 = add(2) 71 | add2(3) // => 5 72 | ``` 73 | 74 | Ambos os casos são um exemplo de Funções de Alta Ordem, mesmo que você nunca tenha usado algo parecido com isso, provavelmente você já viu algo assim em algum lugar. 75 | 76 | **Pure Functions**, ou *Funções Puras*, significa que funções não mudam nenhum valor, elas apenas recebem dados e retornam dados, assim como nossas amadas funções da Matemática. Isso também significa que, se você passar `2` para uma função `f` e ela retornar `10`, ela sempre irá retornar `10`. Não importa o ambiente, threads, ou qualquer ordem de avaliação. Ela não causa nenhum efeito colateral em outras partes do programa, e isso é realmente um conceito poderoso. 77 | 78 | **Closures** significa que você pode salvar algum dado dentro de uma função que é apenas acessível à função de retorno, isto é, a função retornada mantém seu ambiente de execução. 79 | 80 | ```js 81 | var add = function(a){ 82 | return function(b){ 83 | return a + b 84 | } 85 | } 86 | 87 | var add2 = add(2) 88 | add2(3) // => 5 89 | ``` 90 | 91 | Verifique o segundo exemplo de *High-Order Function* novamente. A variável foi *fechada* e é acessível somente para a função retornada. 92 | 93 | **Immutable State** ou *Estado Imutável* signifca que você não pode alterar o estado de forma alguma (embora você possa gerar um novo estado). No seguinte código (em OCaml), você pode usar `x` e `5` alternadamente em seu programa. `x` vai sempre ser `5`. 94 | 95 | ```ocaml 96 | let x = 5;; 97 | x = 6;; 98 | 99 | print_int x;; (* prints 5 *) 100 | ``` 101 | 102 | Isso parece muito mais com um ponto negativo que uma boa característica, mas você vai ver que isso salvará sua vida. 103 | 104 | ## Programação Orientada a Objetos não pode mais nos salvar 105 | 106 | Aquele momento de que teríamos aplicações concorrentes e distribuídas rodando finalmente chegou. 107 | 108 | Infelizmente, nós não estamos prontos: nosso "atual" (i.e., mais usado) modelo para concorrência e paralelismo, embora resolva o problema, ainda traz muita complexidade. 109 | 110 | Para termos melhores aplicações, precisamos de uma maneira simples e confiável para fazer isto. Você se lembra das features de FP mencionados acima? *Pure Functions* (Funções Puras) e *Immutable State* (Imutabilidade de Estado)? Exatamente. Você pode rodar uma função milhares de vezes em diferentes *cores* ou máquinas que ainda assim não terá resultados diferentes dos que teve anteriormente. Sendo assim, você pode usar o mesmo código para rodar em 1 *core* ou em 1k de *cores*. Podemos ser felizes novamente. 111 | 112 | > "Mas por que eu não posso continuar usando POO?" 113 | 114 | Ao menos para concorrência e paralelismo, POO não pode mais te salvar. Isso porque, POO precisa que haja estados mutáveis. Os métodos dos objetos que você invoca, normalmente, servem para alterar o estado do objeto em questão ou de outro. E, trabalhando com concorrência, precisamos adicionar muita complexidade para mantermos sincronizadas todas as threads que utilizam esses objetos concorrentemente ou paralelamente. 115 | 116 | Eu não estou aqui para argumentar que você deve sair do seu paradigma atual para o FP (mesmo que [algumas pessoas digam pra você fazer](https://blog.inf.ed.ac.uk/sapm/2014/03/06/enemy-of-the-state-or-why-oop-is-not-suited-to-large-scale-software/), mas definitivamente você precisa dominá-lo: O Java 8 e C++11 incorporaram as expressões lambda em suas plataformas. Posso afirmar que toda linguagem moderna e ainda mantida vai contar com features de FP em breve. E a maioria delas já tem. 117 | 118 | Vale a pena mencionar que você não vai parar de usar estados mutáveis. Nós precisamos para desenvolver funcionalidades como IO e etc, para termos bons softwares. Porém, a ideia principal que FP provê é: use estados mutáveis apenas quando for necessário. 119 | 120 | ## Eu não trabalho com Cloud, eu realmente preciso de FP? 121 | 122 | Sim. 123 | 124 | Programação Funcional irá te ajudar a escrever melhores programas e raciocinar sobre os problemas que você tem que resolver. 125 | 126 | >"Eu tentei. Mas é muito complexo e tem péssima legibilidade." 127 | 128 | Tudo é difícil no começo. Eu tenho certeza que você ralou para aprender a programar e também para aprender POO. Provavelmente começar a fazer algo em POO foi mais fácil do que escrever seu primeiro programa. Principalmente porque você já estava familiarizado com alguns conceitos comuns, como declaração de variáveis e estruturas de repetição como *for*/*while*. 129 | 130 | Para começar com FP, é quase como começar a aprender a programar de novo (dependendo de qual linguagem você escolher, será definitivamente como aprender a programar do zero). 131 | 132 | Muitos podem argumentar que FP tem má legibilidade. Se você vem de um *background* imperativo, códigos funcionais irão parecer como uma linguagem criptografada. Não porque está realmente criptografado, mas porque você ainda não conhece os conceitos comuns. Uma vez que você dominar esses fundamentos, se tornará muito mais fácil de ler. 133 | 134 | Veja esse código a seguir, escrito em Haskell e JavaScript (usando estilo imperativo): 135 | 136 | ```haskell 137 | guess :: Int -> [Char] 138 | guess 7 = "Much 7 very wow." 139 | guess x = "Ooops, try again." 140 | ``` 141 | 142 | ```js 143 | function guess(x){ 144 | if(x == 7){ 145 | return "Much 7 very wow." 146 | } 147 | else { 148 | return "Oops, try again." 149 | } 150 | } 151 | ``` 152 | 153 | Esse é um programa muito simples que exibe uma mensagem de parabéns quando o usuário digita `7` e uma mensagem de erro para outros valores. Pode parecer magia negra como o Haskell faz isso em apenas 2 linhas de código (ignore a primeira linha por enquanto, é apenas "anotações de tipo"). Mas é muito simples depois que você entende *Pattern Matching* (que não é só implementado em linguagens FP, mas principalmente nelas). 154 | 155 | O que o Haskell está fazendo: 156 | 157 | Se o argumento da função `guess` for igual a `7`, retorna **"Much 7 very wow."** ou retorne **“Ooops, try again.”** para qualquer outro valor. E é exatamente o que o código JavaScript está fazendo, mas o Haskell está identificando através de um "padrão" provido pelo programador. 158 | 159 | Pode parecer que não vale a pena usar isso uma vez que você pode simplesmente usar um if/else. Mas isso é muito poderoso quando estamos trabalhando com estruturas de dados complexas. 160 | 161 | ```haskell 162 | plus1 :: [Int] -> [Int] 163 | plus1 [] = [] 164 | plus1 (x:xs) = x + 1 : plus1 xs 165 | 166 | -- plus1 [0,1,2,3] 167 | -- > [1,2,3,4] 168 | ``` 169 | 170 | No programa acima, **plus1** é uma função que recebe uma lista de Ints e e adiciona `1` para cada elemento da lista. Ele identifica o padrão de uma lista vazia `[]` (e retorna outra lista vazia, já que não há elementos para adicionar `1`) e quando ele identificar o padrão de uma lista com elementos: nomeia o primeiro elemento da lista como **x** e os elementos restantes como **xs**. Então, executa a soma e concatena com o retorno da chamada recursiva. 171 | 172 | Eu tenho certeza que você passaria por maus bocados tentando reescrever a função `plus1` usando estilo imperativo em duas linhas de código e ainda deixá-lo legível. 173 | 174 | 175 | ## Então, vamos começar 176 | 177 | Exite muito conteúdo por aí falando sobre Programação Funcional, mas alguns que você não pode perder são: 178 | 179 | * [Principles of Functional Programming in Scala](https://www.coursera.org/course/progfun) 180 | 181 | * [Introduction to Functional Programming](https://www.edx.org/course/introduction-functional-programming-delftx-fp101x) ([Contents](https://github.com/fptudelft/FP101x-Content)) 182 | * [Paradigms of Computer Programming — Fundamentals](https://www.edx.org/course/paradigms-computer-programming-louvainx-louv1-1x#.VKXX2orF_rd) 183 | 184 | Infelizmente, eles costumam iniciar no fim do ano, mas você pode seguir o conteúdo e os videos que estão disponíveis no youtube. 185 | 186 | Por outro lado, se você prefere livros, eu recomendo fortemente esses a seguir: 187 | 188 | * [Structure and Interpretation of Computer Programs](https://mitpress.mit.edu/sicp/full-text/book/book.html) 189 | 190 | * [How to Design Programs](http://htdp.org/) 191 | 192 | * [Concepts, Techniques, and Models of Computer Programming](http://www.amazon.com/Concepts-Techniques-Models-Computer-Programming/dp/0262220695) 193 | 194 | Boa Sorte no seu novo ano Funcional! ☺ 195 | -------------------------------------------------------------------------------- /javascript/003-escopo-de-variavel-js-e-hoisting-explicado.md: -------------------------------------------------------------------------------- 1 | # Escopo e _Hoisting_ de Variáveis no JavaScript Explicados 2 | 3 | * **Artigo Original**: [JavaScript Variable Scope and Hoisting Explained](http://javascriptissexy.com/javascript-variable-scope-and-hoisting-explained/) 4 | * **Tradução**: [Eric Douglas](https://github.com/ericdouglas) 5 | 6 | Nesta postagem, iremos aprender sobre escopo e hoisting (hasteamento) de variáveis no JavaScript e tudo sobre as idiossincrasias (peculiaridades) de ambos. 7 | 8 | É imperativo que nós tenhamos entendimento de como o escopo e o hasteamento de variável funcionam no JavaScript, se quisermos entender bem o JS. Estes conceitos podem parecer óbvios, mas não são. Há algumas importantes sutilezas que nós devemos compreender, se realmente quisermos ser desenvolvedores JavaScript bem sucedidos. 9 | 10 | ##Escopo de Variáveis 11 | 12 | Um escopo de variável é o contexto no qual a variável existe. O escopo especifica de onde você pode acessar uma variável e se você tem acesso à variável naquele contexto. 13 | 14 | Variáveis têm ou um escopo local ou um escopo global. 15 | 16 | ##Variáveis Locais (Escopo Nível-de-Função) 17 | 18 | Ao contrário da maioria das linguagens de programação, o JavaScript não tem um escopo em nível-de-bloco (variáveis com o escopo envolto por chaves); como alternativa, no JavaScript temos escopo por nível-de-função. As variáveis declaradas dentro de uma função são variáveis locais, e são somente acessíveis por dentro dessa função ou por funções dentro dessa função. Veja a minha postagem de [Closures](https://github.com/cerebrobr/traduz-ai/blob/master/javascript/004-entenda-closures-no-javaScript-com-facilidade.md) para saber mais em como acessar variáveis em funções exteriores a partir de funções interiores. 19 | 20 | Demonstração de Escopo de Nível-de-Função 21 | 22 | ```javascript 23 | var name = "Richard"; 24 | 25 | function showName() { 26 | var name = "Jack"; // variável local; somente acessível na função showName 27 | console.log(name); // Jack 28 | } 29 | 30 | console.log(name); // Richard: a variável global 31 | ``` 32 | 33 | Sem Escopo de Nível-de-Bloco 34 | 35 | ```javascript 36 | var name = "Richard"; 37 | // O bloco nesta condicional if não cria um contexto local para a variável name 38 | if (name) { 39 | name = "Jack"; // este name é a variável global name e está sendo alterada para "Jack" aqui 40 | console.log(name); // Jack: ainda como a variável global 41 | } 42 | 43 | // Aqui, a variável name é a mesma variável global name, mas ela foi modificada na condicional if 44 | console.log(name); // Jack 45 | ``` 46 | 47 | ### Se você não declarar as suas variáveis locais, encrenca está perto 48 | 49 | Sempre declare suas variáveis locais antes de usá-las. Aliás, você deveria usar o [JSHint](http://www.jshint.com/) para verificar seu código por erros de sintaxe e guias de estilo. Aqui está o problema ao não declarar variáveis locais: 50 | 51 | ```javascript 52 | // Se você não declarar suas variáveis locais com a palavra-chave var, 53 | // elas se tornam parte do escopo global 54 | var name = "Michael Jackson"; 55 | 56 | function showCelebrityName() { 57 | console.log(name); 58 | } 59 | 60 | function showOrdinaryPersonName() { 61 | // Note a ausência da palavra-chave var, 62 | // tornando esta variável global: 63 | name = "Johnny Evers"; 64 | console.log(name); 65 | } 66 | 67 | showCelebrityName(); // Michael Jackson 68 | 69 | // name não é uma variável local, ele simplesmente muda a variável global name 70 | showOrdinaryPersonName(); // Johnny Evers 71 | 72 | // A variável global é agora Johnny Evers, não mais o name da celebridade Michael Jackson 73 | showCelebrityName(); // Johnny Evers 74 | 75 | // A solução é declarar sua variável local com a palavra-chave var 76 | function showOrdinaryPersonName() { 77 | // Agora name é sempre uma variável local 78 | // e não irá sobrescrever a variável global 79 | var name = "Johnny Evers"; 80 | console.log(name); 81 | } 82 | ``` 83 | 84 | ### Variáveis locais têm prioridade sobre variáveis globais nas funções 85 | 86 | Se você declarar uma variável global e uma variável local com o mesmo nome, a variável local terá prioridade quando você tentar usá-la dentro de uma função (escopo local): 87 | 88 | ```javascript 89 | var name = "Paul"; 90 | 91 | function users() { 92 | // Aqui, a variável name é local 93 | // e prevalece sobre a mesma variável name no escopo global 94 | var name = "Jack"; 95 | 96 | // A busca por name começa bem aqui dentro da função 97 | // antes de tentar enxergar fora da função no escopo global 98 | console.log(name); 99 | } 100 | 101 | users(); // Jack 102 | ``` 103 | 104 | ## Variáveis Globais 105 | 106 | Todas as variáveis declaradas fora de uma função estão no escopo global. No navegador, que é onde estamos interessados como desenvolvedores front-end, o contexto ou escopo global é o objeto _window_ (ou o documento HTML inteiro). 107 | 108 | - Qualquer variável declarada ou inicializada fora de uma função é uma variável global, e estará portanto disponível para toda a aplicação. Por exemplo: 109 | 110 | ```javascript 111 | // Para declarar uma variável global, você pode utilizar quaisquer das seguintes estratégias: 112 | var myName = "Richard"; 113 | 114 | // ou mesmo 115 | firstName = "Richard"; 116 | 117 | // ou 118 | var name; 119 | name; 120 | ``` 121 | 122 | É importante notar que todas as variáveis globais são anexadas no objeto _window_. Então, todas as variáveis globais que nós declaramos podem ser acessadas pelo object _window_ como assim: 123 | 124 | ```javascript 125 | console.log(window.myName); // Richard; 126 | 127 | // ou 128 | console.log("myName" in window); // true 129 | console.log("firstName" in window); // true 130 | ``` 131 | 132 | - Se uma variável é inicializada (atribuída com um valor) sem primeiro ser declarada com a palavra-chave var, ela é automaticamente adicionada ao contexto global, sendo deste modo uma variável global: 133 | 134 | ```javascript 135 | function showAge() { 136 | // age é uma variável global porque ela não foi declarada 137 | // com a palavra-chave var dentro da função: 138 | age = 90; 139 | console.log(age); 140 | } 141 | 142 | // age está no contexto global, portanto está disponível aqui também: 143 | console.log(age); // 90 144 | ``` 145 | 146 | Demonstração de variáveis que estão no Escopo Global mesmo que pareça o contrário: 147 | 148 | ```javascript 149 | // Ambas variáveis firstName estão no escopo global, 150 | // mesmo embora a segunda esteja envolta pelo bloco {}: 151 | var firstName = "Richard"; 152 | { 153 | var firstName = "Bob"; 154 | } 155 | 156 | // Para reiterar: JavaScript não tem escopo por nível-de-bloco 157 | 158 | // A segunda declaração de firstName simplesmente redeclara e sobrescreve a primeira 159 | console.log(firstName); // Bob 160 | ``` 161 | 162 | Outro exemplo: 163 | 164 | ```javascript 165 | for (var i = 1; i <= 10; ++i) { 166 | console.log(i); // imprime 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 167 | } 168 | 169 | // A variável i é uma variável global e está acessível 170 | // na seguinte função com o último valor que foi-lhe atribuído acima 171 | function aNumber() { 172 | console.log(i); 173 | } 174 | 175 | // A variável i na função aNumber abaixo é a variável global i que foi alterada no laço acima. 176 | // Seu último valor foi 11, atribuído um momento antes da saída do laço: 177 | aNumber(); // 11 178 | ``` 179 | 180 | ### Variáveis de setTimeout são Executadas no Escopo Global 181 | Note que todas as funções no setTimeout são executadas no escopo global. Isto é ligeiramente complicado; considere isto: 182 | 183 | ```javascript 184 | // O uso do objeto "this" dentro da função setTimeout refere-se ao objeto Window, não ao myObj 185 | 186 | var highValue = 200; 187 | var constantVal = 2; 188 | var myObj = { 189 | highValue: 20, 190 | constantVal: 5, 191 | calculateIt: function () { 192 | setTimeout (function () { 193 | console.log(this.constantVal * this.highValue); 194 | }, 2000); 195 | } 196 | }; 197 | 198 | // O objeto "this" na função setTimeout usou as variáveis globais highValue e constantVal, 199 | // porque a referência ao "this" na função setTimeout refere-se ao objeto global window, 200 | // não ao objeto myObj como anteciparíamos. 201 | 202 | myObj.calculateIt(); // 400 203 | 204 | // Este é um ponto importante a ser lembrado! 205 | ``` 206 | 207 | ### Não Polua o Escopo Global 208 | 209 | Se você quer se tornar um mestre em JavaScript, o que certamente você quer ser (caso contrário você estaria assistindo 'Honey Boo Boo' neste exato momento), você tem que saber que é importante evitar criar muitas variáveis no escopo global, tal como este: 210 | 211 | ```javascript 212 | // Estas duas variáveis estão no escopo global e elas não deveriam estar aqui: 213 | var firstName, lastName; 214 | 215 | function fullName() { 216 | console.log("Full name: " + firstName + " " + lastName); 217 | } 218 | ``` 219 | 220 | Este é o código melhorado e a maneira apropriada de se evitar poluir o escopo global: 221 | 222 | ```javascript 223 | // Declare as variáveis dentro da função onde serão variáveis locais: 224 | function fullName() { 225 | var firstName = "Michael", lastName = "Jackson"; 226 | 227 | console.log("Full Name: " + firstName + " " + lastName); 228 | } 229 | ``` 230 | 231 | Neste último exemplo, a função fullName está no escopo global. 232 | 233 | ## Hasteamento de Variáveis (Variable Hoisting) 234 | 235 | Todas declarações de variáveis são hasteadas (erguidas e declaradas) ao topo da função se definida dentro duma função; ou no topo do contexto global se definida fora duma função. 236 | 237 | É importante saber que somente declarações de variáveis são hasteadas ao topo, não a inicialização ou as atribuições (quando para uma variável é atribuído um valor) de variáveis. 238 | 239 | Exemplo de Hasteamento de Variável: 240 | 241 | ```javascript 242 | function showName() { 243 | console.log("First Name: " + name); 244 | var name = "Ford"; 245 | console.log("Last Name: " + name); 246 | } 247 | 248 | showName (); 249 | // First Name: undefined 250 | // Last Name: Ford 251 | 252 | // A razão para a primeira impressão ser undefined é que a variável local name foi hasteada ao topo da função 253 | // Que significa que é esta a variável local que é chamada na primeira vez. 254 | // Veja como o código realmente é processado pela engine (motor) JavaScript 255 | 256 | function showName() { 257 | // name é hasteada (note que está indefinida (undefined) até este ponto, 258 | // já que a atribuição acontece depois mais abaixo): 259 | var name; 260 | console.log("First Name: " + name); // First Name: undefined 261 | 262 | name = "Ford"; // é atribuído um valor a name 263 | 264 | // Agora name é Ford 265 | console.log("Last Name: " + name); // Last Name: Ford 266 | } 267 | ``` 268 | 269 | ### Declaração de Função Sobrescreve Declaração de Variável Quando Hasteada 270 | 271 | Ambas declarações de funções e variáveis são hasteadas para o topo do escopo que as contém. E a declaração de função tem prioridade sobre declarações de variável (mas não sobre atribuição de variável). Como notado acima, atribuição de variável não é hasteada, e nem atribuição de função. Como um lembrete, isto é uma atribuição de função: `var myFunction = function () {};`. 272 | Aqui temos um exemplo básico para demonstração: 273 | 274 | ```javascript 275 | // Tanto a variável quanto a função são nomeadas de myName: 276 | var myName; 277 | 278 | function myName() { 279 | console.log("Rich"); 280 | } 281 | 282 | // A declaração da função sobrescreve a variável myName: 283 | console.log(typeof myName); // function 284 | ``` 285 | 286 | ```javascript 287 | // Mas neste exemplo, a atribuição da variável sobrescreve a declaração da função 288 | 289 | // Isso é a atribuição de variável (inicialização) que sobrescreve a declaração da função: 290 | var myName = "Richard"; 291 | 292 | function myName() { 293 | console.log("Rich"); 294 | } 295 | 296 | console.log(typeof myName); // string 297 | ``` 298 | 299 | É importante notar que as expressões função, tais como o exemplo abaixo, não são hasteadas: 300 | 301 | ```javascript 302 | var myName = function() { 303 | console.log("Rich"); 304 | }; 305 | ``` 306 | 307 | No modo estrito (`"strict mode";`), um erro ocorrerá se você atribuir a uma variável algum valor sem primeiro declarar a variável. Sempre declare as suas variáveis! 308 | 309 | Sê bom. Durma bem. E curta programar! 310 | -------------------------------------------------------------------------------- /series/voce-nao-precisa-de-jquery/02-manipulacao-dom.md: -------------------------------------------------------------------------------- 1 | # Manipulação do DOM 2 | 3 | * **Artigo original**: [DOM Manipulation](http://blog.garstasio.com/you-dont-need-jquery/dom-manipulation/) 4 | * **Tradução**: [Eric Cristhiano](https://github.com/ericcristhiano) 5 | 6 | Anteriormente, [aprendemos como selecionar elementos sem depender do jQuery](01-seletores.md), mas o que aprendemos sobre mudar elementos? Sobre criar novos elementos? Que tal mudar os elementos para outro lugar na página? Você pode ficar feliz em saber que tudo isso, e mais, também é possível sem utilizar o jQuery. A web API nos fornece todas as ferramentas que precisamos, mais uma vez. 7 | Você verá que algumas manipulações no DOM são triviais sem o auxílio do jQuery ou qualquer outra biblioteca. No entanto, outras podem ser um pouco mais complicadas. Este é um momento de destacar (novamente) que não estou tentando derrubar o jQuery, nem vou afirmar que é inútil ou completamente desnecessário. A intenção desses posts é para informa-lo como trabalhar com o navegador sem jQuery, se você preferir. Você pode concluir que, em muitos casos, uma biblioteca grande, como o jQuery, na maior parte não vai ser utilizada, e pode ser dispensada. 8 | 9 | 1. [Criando Elementos](#criando-elementos) 10 | 2. [Inserindo Elementos antes & depois](#inserindo-elementos-antes-e-depois) 11 | 3. [Inserindo elementos como filhos](#inserindo-elementos-como-filhos) 12 | 4. [Movendo elementos](#movendo-elementos) 13 | 5. [Removendo elementos](#removendo-elementos) 14 | 6. [Adicionando e removendo classes CSS](#adicionando-e-removendo-classes-css) 15 | 7. [Adicionando/removendo/alterando atributos](#adicionando-removendo-alterando-atributos) 16 | 8. [Adicionando e alterando conteúdo](#adicionando-e-alterando-conteudo) 17 | 9. [Adicionando/atualizando estilo dos elementos](#adicionando-atualizando-estilo-dos-elementos) 18 | 10. [Micro-bibliotecas para ajuda](#micro-bibliotecas-para-ajuda) 19 | 11. [Próximo](#proximo) 20 | 21 | ##
Criando Elementos 22 | 23 | *jQuery* 24 | 25 | ``` 26 | $('
'); 27 | ``` 28 | 29 | *DOM API* 30 | 31 | ``` 32 | // IE 5.5+ 33 | document.createElement('div'); 34 | ``` 35 | 36 | Wow, isso foi muito fácil. O jQuery nos poupou algumas teclas, mas isso dificilmente vale o tamanho da biblioteca. 37 | 38 | ## Inserindo elementos antes e depois 39 | 40 | Vamos criar um elemento e inseri-lo após o outro elemento específico. 41 | Então, vamos começar com: 42 | 43 | ``` 44 |
45 |
46 |
47 | ``` 48 | 49 | E nós gostaríamos de criar um novo elemento com um ID '1.1' e inseri-lo entre as duas primeiras divs, dando-nos isto: 50 | 51 | ``` 52 |
53 |
54 |
55 |
56 | ``` 57 | 58 | *jQuery* 59 | 60 | ``` 61 | $('#1').after('
'); 62 | ``` 63 | 64 | *DOM API* 65 | 66 | ``` 67 | // IE 4+ 68 | document.getElementById('1') 69 | .insertAdjacentHTML('afterend', '
'); 70 | ``` 71 | 72 | Há! Tome ISSO jQuery! Muito fácil em todos os navegadores apenas contanto com as ferramentas incorporadas no browser. 73 | 74 | Ok, mas e se quisermos inserir um novo elemento ANTES da primeira div, dando-nos isso: 75 | 76 | ``` 77 |
78 |
79 |
80 |
81 | ``` 82 | 83 | *jQuery* 84 | 85 | ``` 86 | $('#1').before('
'); 87 | ``` 88 | 89 | *DOM API* 90 | 91 | ``` 92 | // IE 4+ 93 | document.getElementById('1') 94 | .insertAdjacentHTML('beforebegin', '
'); 95 | ``` 96 | 97 | Praticamente igual ao último, com a exceção de uma chamada de método diferente para jQuery e um diferente parâmetro para a abordagem JavaScript puro. 98 | 99 | ## Inserindo elementos como filhos 100 | 101 | Vamos dizer que temos isso: 102 | 103 | ``` 104 |
105 |
106 |
107 | ``` 108 | 109 | ...e queremos criar um novo elemento e torna-lo o primeiro filho de parent, como em: 110 | 111 | ``` 112 |
113 |
114 |
115 |
116 | ``` 117 | 118 | *jQuery* 119 | 120 | ``` 121 | $('#parent').prepend('
'); 122 | ``` 123 | 124 | *DOM API* 125 | 126 | ``` 127 | // IE 4+ 128 | document.getElementById('parent') 129 | .insertAdjacentHTML('afterbegin', '
'); 130 | ``` 131 | 132 | ...ou criar um novo elemento e torna-lo o último filho de #parent 133 | 134 | ``` 135 |
136 |
137 |
138 |
139 | ``` 140 | 141 | *jQuery* 142 | 143 | ``` 144 | $('#parent').append('
'); 145 | ``` 146 | 147 | *DOM API* 148 | 149 | ``` 150 | // IE 4+ 151 | document.getElementById('parent') 152 | .insertAdjacentHTML('beforeend', '
'); 153 | ``` 154 | 155 | Tudo isso parece muito com a seção anterior que tratou com a inserção de novos elementos. Novamente, é muito simples fazer tudo isso, cross-browser, sem qualquer ajuda do jQuery (ou qualquer outra biblioteca). 156 | 157 | ## Movendo elementos 158 | 159 | Considere a seguinte marcação: 160 | 161 | ``` 162 |
163 |
164 |
165 |
166 |
167 |
168 | ``` 169 | 170 | E se nós quisermos mudar o #orphan para o último filho do #parent? Isso nos daria isso: 171 | 172 | ``` 173 |
174 |
175 |
176 |
177 |
178 |
179 | ``` 180 | 181 | *jQuery* 182 | 183 | ``` 184 | $('#parent').append($('#orphan')); 185 | ``` 186 | 187 | *DOM API* 188 | 189 | ``` 190 | // IE 5.5+ 191 | document.getElementById('parent') 192 | .appendChild(document.getElementById('orphan')); 193 | ``` 194 | 195 | Bem simples, sem jQuery. Mas e se quiséssemos fazer #orphan o primeiro filho de #parent, dando-nos isso: 196 | 197 | ``` 198 |
199 |
200 |
201 |
202 |
203 |
204 | ``` 205 | 206 | *jQuery* 207 | 208 | ``` 209 | $('#parent').prepend($('#orphan')); 210 | ``` 211 | 212 | *DOM API* 213 | 214 | ``` 215 | // IE 5.5+ 216 | document.getElementById('parent') 217 | .insertBefore(document.getElementById('orphan'), document.getElementById('c1')); 218 | ``` 219 | 220 | Podemos ainda completar isso em uma linha, mas é um pouco menos intuitivo e verboso sem jQuery, ainda, não tão mau. 221 | 222 | ## Removendo elementos 223 | 224 | Como podemos remover um elemento do DOM? Vamos dizer que nós sabemos que um elemento com o ID “foobar” existe. Vamos destruí-lo. 225 | 226 | *jQuery* 227 | 228 | ``` 229 | $('#foobar').remove(); 230 | ``` 231 | 232 | *DOM API* 233 | 234 | ``` 235 | // IE 5.5+ 236 | document.getElementById('foobar').parentNode 237 | .removeChild(document.getElementById('foobar')); 238 | ``` 239 | 240 | A abordagem DOM API é certamente um pouco mais extensa e feia, mas funciona! Note que não temos que saber do elemento pai, o que é bom. 241 | 242 | ## Adicionando & Removendo Classes CSS 243 | 244 | Temos um simples elemento: 245 | 246 | ``` 247 |
248 | ``` 249 | 250 | ...vamos adicionar uma classe CSS chamada “bold” neste elemento, dando-nos: 251 | ``` 252 |
253 | ``` 254 | 255 | *jQuery* 256 | 257 | ``` 258 | $('#foo').addClass('bold'); 259 | ``` 260 | 261 | *DOM API* 262 | 263 | ``` 264 | // IE 5.5+ 265 | // All modern browsers, with the exception of IE9 266 | document.getElementById('foo').classList.add('bold'); 267 | 268 | // All browsers 269 | document.getElementById('foo').className += 'bold'; 270 | ``` 271 | 272 | Vamos remover essa classe agora: 273 | 274 | *jQuery* 275 | 276 | ``` 277 | $('#foo').removeClass('bold'); 278 | ``` 279 | 280 | *DOM API* 281 | 282 | ``` 283 | // All modern browsers, with the exception of IE9 284 | document.getElementById('foo').classList.remove('bold'); 285 | 286 | 287 | // All browsers 288 | document.getElementById('foo').className = 289 | document.getElementById('foo').className.replace(/^bold$/, ''); 290 | ``` 291 | 292 | Para o IE 10 e superior, é praticamente o mesmo entre jQuery e API Web. 293 | 294 | ## Adicionando/Removendo/Alterando Atributos 295 | 296 | Vamos iniciar com um simples elemento, como este: 297 | 298 | ``` 299 |
300 | ``` 301 | 302 | Agora, vamos dizer quer ```
``` na verdade, funciona como um botão. Nós deveríamos definir o atributo ```role``` para tornar este elemento mais acessível. 303 | 304 | *jQuery* 305 | 306 | ``` 307 | $('#foo').attr('role', 'button'); 308 | ``` 309 | 310 | *DOM API* 311 | 312 | ``` 313 | // IE 5.5+ 314 | document.getElementById('foo').setAttribute('role', 'button'); 315 | ``` 316 | 317 | Em ambos casos, um novo atribute pode ser criado, ou um atributo existente pode ser atualizado utilizando o mesmo código. 318 | E se o comportamento de nossa ```
``` muda, e não tem mais a função de um botão. De fato, é apenas uma ```
``` agora com algum texto ou marcação. Vamos remover aquela ```role```... 319 | 320 | *jQuery* 321 | 322 | ``` 323 | $('#foo').removeAttr('role'); 324 | ``` 325 | 326 | *DOM API* 327 | 328 | ``` 329 | // IE 5.5+ 330 | document.getElementById('foo').removeAttribute('role'); 331 | ``` 332 | 333 | ## Adicionando & Alterando conteúdo 334 | 335 | Agora, temos a seguinte marcação: 336 | 337 | ``` 338 |
Hi there!
339 | ``` 340 | 341 | ...mas, nós queremos atualizar o texto para “Goodbye!”. 342 | 343 | *jQuery* 344 | 345 | ``` 346 | $('#foo').text('Goodbye!'); 347 | ``` 348 | 349 | Note que você também pode facilmente recuperar o texto atual do elemento chamando ```text``` sem nenhum parâmetro. 350 | 351 | *DOM API* 352 | 353 | ``` 354 | // IE 5.5+ 355 | document.getElementById('foo').innerHTML = 'Goodbye!'; 356 | 357 | // IE 5.5+ but NOT Firefox 358 | document.getElementById('foo').innerText = 'GoodBye!'; 359 | 360 | // IE 9+ 361 | document.getElementById('foo').textContent = 'Goodbye!'; 362 | ``` 363 | 364 | Ambas propriedades acima retornarão HTML/texto atual. 365 | A vantagem de usar o ```innerText``` ou ```textContent``` é que qualquer HTML é escapado, o que é uma grande característica seu o conteúdo é fornecido pelo usuário e você quer apenas incluir o texto como conteúdo para o elemento selecionado. 366 | 367 | ## Adicionando/Atualizando Estilo dos Elementos 368 | 369 | Geralmente, adicionar códigos CSS “inline” ou com javascript é um ["código ruim"](https://en.wikipedia.org/wiki/Code_smell), mas pode ser necessário em casos únicos. Para esses casos, vou lhe mostrar como isso pode ser feito com jQuery e DOM API. 370 | 371 | Dado um simples elemento com algum texto: 372 | 373 | ``` 374 | Attention! 375 | ``` 376 | 377 | ...gostaríamos de fazê-lo destacar-se um pouco mais, tornando-o negrito. 378 | 379 | *jQuery* 380 | 381 | ``` 382 | $('#note').css('fontWeight', 'bold'); 383 | ``` 384 | 385 | Note que você também pode facilmente recuperar o texto atual do elemento chamando “text” sem nenhum parâmetro. 386 | 387 | *DOM API* 388 | 389 | ``` 390 | // IE 5.5+ 391 | document.getElementById('note').style.fontWeight = 'bold'; 392 | ``` 393 | 394 | Na verdade, eu prefiro a abordagem DOM API nesse caso. Parece muito mais intuitivo que o método ```css``` do jQuery. 395 | 396 | ## Micro-bibliotecas para Ajuda 397 | 398 | Então, quer saber? Você realmente não precisa de jQuery para manipulação de DOM cross-browser. Percebo que o jQuery pode fazer códigos mais complexos um pouco mais fáceis, mas se você está realmente interessado com tarefas mais complexas de manipulação de DOM, então considere utilizar em uma biblioteca menor que foca principalmente nisso. Algumas escolhas são o [jBone](https://github.com/kupriyanenko/jbone) e [dom.js](https://github.com/dkraczkowski/dom.js). Não há nada de errado em criar sua biblioteca também. Manipulação do DOM não é tão difícil como você pode imaginar. 399 | 400 | 401 | ## Próximo Post 402 | 403 | [Ajax Requests](http://blog.garstasio.com/you-dont-need-jquery/ajax/) (Em inglês) -------------------------------------------------------------------------------- /javascript/010-uma-suave-introducao-ao-javascript-parte-2.md: -------------------------------------------------------------------------------- 1 | # Uma Suave Introdução ao JavaScript Funcional: Parte 2 2 | 3 | * **Artigo Original**: [A GENTLE INTRODUCTION TO FUNCTIONAL JAVASCRIPT: PART 2](http://jrsinclair.com/articles/2016/gentle-introduction-to-functional-javascript-arrays/) 4 | * **Tradução**: [Eric Douglas](https://github.com/ericdouglas) 5 | 6 | > *Escrito por James Sinclair em 30 de Janeiro de 2016* 7 | 8 | Essa é a parte 2 de uma série de 4 artigos introduzindo a programação funcional no JavaScript. No artigo anterior, nós vimos como as funções podem ser usadas para fazer abstrações de código de forma mais fácil. Nesse artigo vamos aplicar essas técnicas em listas. 9 | 10 | - [Parte 1: Blocos fundamentais e motivação](009-uma-suave-introducao-ao-javascript-parte-1.md) 11 | - Parte 2: Trabalhando com Arrays e Listas (esse artigo) 12 | - [Parte 3: Funções para fazer funções](011-uma-suave-introducao-ao-javascript-parte-3.md) 13 | - Parte 4: Fazendo isso com estilo 14 | 15 | ## Trabalhando com Arrays e Listas 16 | Relembre que no artigo anterior, falamos sobre código DRY. Vimos que funções são úteis para juntar grupos de ações que podem se repetir. Mas e se estivermos repetindo a mesma função várias vezes? Por exemplo: 17 | 18 | ```js 19 | function addColour(colour) { 20 | var rainbowEl = document.getElementById('rainbow'); 21 | var div = document.createElement('div'); 22 | div.style.paddingTop = '10px'; 23 | div.style.backgroundColour = colour; 24 | rainbowEl.appendChild(div); 25 | } 26 | 27 | addColour('red'); 28 | addColour('orange'); 29 | addColour('yellow'); 30 | addColour('green'); 31 | addColour('blue'); 32 | addColour('purple'); 33 | ``` 34 | 35 | A função `addColor` é chamada várias vezes. Estamos nos repetindo - algo que queremos evitar. Uma forma de evitar isso é movendo a lista de cores para um array, e chamar `addColor` em um loop `for`: 36 | 37 | ```js 38 | var colours = [ 39 | 'red', 'orange', 'yellow', 40 | 'green', 'blue', 'purple' 41 | ]; 42 | 43 | for (var i = 0; i < colours.length; i = i + 1) { 44 | addColour(colours[i]); 45 | } 46 | ``` 47 | 48 | Esse código é perfeitamente aceitável. Ele finaliza o trabalho e é menos repetitivo que a versão anterior. Mas não é particularmente expressivo. Temos que dar ao computador instruções muito específicas sobre criar uma variável de indicação (*index*) e incrementá-la, verificando se é hora de parar. E se pudéssemos encapsular todo esse loop `for` em uma função? 49 | 50 | ### For-Each (Para Cada) 51 | Uma vez que o JavaScript nos permite passar uma função como parâmetro para outra função, escrever uma função `forEach` é relativamente simples: 52 | 53 | ```js 54 | function forEach(callback, array) { 55 | for (var i = 0; i < array.length; i = i + 1) { 56 | callback(array[i], i); 57 | } 58 | } 59 | ``` 60 | 61 | Essa função recebe outra função, `callback`, como um parâmetro e a chama em cada item do array. 62 | 63 | Agora, com nosso exemplo, nós queremos rodar a função `addColor` em cada item no array. Usando nossa função `forEach` podemos expressar essa intenção em apenas uma linha: 64 | 65 | ```js 66 | forEach(addColour, colours); 67 | ``` 68 | 69 | Chamar uma função em cada item de um array é uma ferramenta tão útil que implementações modernas do JavaScript incluem isso como uma função nativa nos arrays. Então ao invés de usarmos nossa própria função `forEach`, podemos usar a função nativa dessa forma: 70 | 71 | ```js 72 | var colours = [ 73 | 'red', 'orange', 'yellow', 74 | 'green', 'blue', 'purple' 75 | ]; 76 | 77 | colours.forEach(addColour); 78 | ``` 79 | 80 | Você pode achar mais informações sobre o método nativo [`forEach` na referência JavaScript da MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach) 81 | 82 | ### Map 83 | Nossa função `forEach` é útil, mas é de alguma forma limitada. Se a função *callback* que passamos retornar um valor, `forEach` apenas ignora-o. Com um pequeno ajuste, podemos alterar nossa função `forEach` e ela vai nos dar qualquer valor que a função callback retornar. Vamos ter então um novo array com o valor correspondente a cada valor no array original. 84 | 85 | Vamos ver um exemplo. Se temos um arrays com IDs, e queremos pegar o elemento correspondente a cada um deles. Em uma solução da forma procedural usaríamos um loop `for`: 86 | 87 | ```js 88 | var ids = ['unicorn', 'fairy', 'kitten']; 89 | var elements = []; 90 | for (var i = 0; i < ids.length; i = i + 1) { 91 | elements[i] = document.getElementById(ids[i]); 92 | } 93 | // elements now contains the elements we are after 94 | ``` 95 | 96 | Novamente, tivemos que dizer ao computador como criar uma variável *index* e incrementá-la - detalhes que realmente não devemos nos preocupar. Vamos refatorar o loop `for` assim como fizemos com `forEach` e colocá-lo numa função chamada `map`: 97 | 98 | ```js 99 | var map = function(callback, array) { 100 | var newArray = []; 101 | for (var i = 0; i < array.length; i = i + 1) { 102 | newArray[i] = callback(array[i], i); 103 | } 104 | return newArray; 105 | } 106 | ``` 107 | 108 | A função `map` pega funções pequenas e triviais, tornando-as em funções super-herói - ela multiplica a efetividade da função aplicando-a em um array inteiro apenas com uma chamada. 109 | 110 | Assim como `forEach`, `map` é tão útil que implementações modernas do JavaScript a tem como um método nativo para objetos array. Você pode chamar o método nativo da seguinte forma: 111 | 112 | ```js 113 | var ids = ['unicorn', 'fairy', 'kitten']; 114 | var getElement = function(id) { 115 | return document.getElementById(id); 116 | }; 117 | var elements = ids.map(getElement); 118 | ``` 119 | 120 | Você pode ler mais sobre o método nativo [`map` na referência JavaScript da MDN.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) 121 | 122 | ### Reduce 123 | `map` é muito útil, mas nós podemos fazer uma função ainda mais poderosa se pegarmos um array inteiro e retornar apenas um valor. Isso pode parecer inicialmente um pouco contraintuitivo - como uma função que retorna um valor ao invés de vários é mais *poderosa*? Para descobrir o porquê, temos que primeiro olhar como essa função trabalha. 124 | 125 | Para ilustrar, vamos considerar dois problemas similares: 126 | 127 | 1. Dado um array de números, calcule a soma; e 128 | 1. Dado um array de palavras, junte-as com um espaço entre cada palavra. 129 | 130 | Isso pode parecer exemplos bobos, triviais - e eles são. Mas tenha paciência comigo, após vermos como a função `reduce` trabalha, nós vamos aplicá-la de formas mais interessantes. 131 | 132 | A forma "procedural" de resolver esses problemas é, novamente, com loops `for`: 133 | 134 | ```js 135 | // Given an array of numbers, calculate the sum 136 | var numbers = [1, 3, 5, 7, 9]; 137 | var total = 0; 138 | for (var i = 0; i < numbers.length; i = i + 1) { 139 | total = total + numbers[i]; 140 | } 141 | // total is 25 142 | 143 | // Given an array of words, join them together with a space between each word. 144 | var words = ['sparkle', 'fairies', 'are', 'amazing']; 145 | var sentence = ''; 146 | for (i = 0; i < words.length; i++) { 147 | sentence = sentence + ' ' + words[i]; 148 | } 149 | // ' sparkle fairies are amazing' 150 | ``` 151 | 152 | Essas duas soluções tem muito em comum. Ambas usam um loop `for` para iterar sobre um array; ambas tem uma variável trabalhando ( `total` e `sentence`); e ambas definem o valor trabalhado com um valor inicial. 153 | 154 | Vamos refatorar a parte interior de cada loop, e tornar isso em uma função: 155 | 156 | ```js 157 | var add = function(a, b) { 158 | return a + b; 159 | } 160 | 161 | // Given an array of numbers, calculate the sum 162 | var numbers = [1, 3, 5, 7, 9]; 163 | var total = 0; 164 | for (i = 0; i < numbers.length; i = i + 1) { 165 | total = add(total, numbers[i]); 166 | } 167 | // total is 25 168 | 169 | function joinWord(sentence, word) { 170 | return sentence + ' ' + word; 171 | } 172 | 173 | // Given an array of words, join them together with a space between each word. 174 | var words = ['sparkle', 'fairies', 'are', 'amazing']; 175 | var sentence = ''; 176 | for (i = 0; i < words.length; i++) { 177 | sentence = joinWord(sentence, words[i]); 178 | } 179 | // 'sparkle fairies are amazing' 180 | ``` 181 | 182 | Isso é muito mais conciso e o padrão ficou claro. Ambas funções interiores pegam a variável de trabalho como primeiro parâmetro e o elemento atual do array como segundo. Agora que conseguimos ver o padrão de forma mais clara, nós podemos mover os loops `for` para dentro da função: 183 | 184 | ```js 185 | var reduce = function(callback, initialValue, array) { 186 | var working = initialValue; 187 | for (var i = 0; i < array.length; i = i + 1) { 188 | working = callback(working, array[i]); 189 | } 190 | return working; 191 | }; 192 | ``` 193 | 194 | Agora que temos nossa função `reduce`, vamos usá-la: 195 | 196 | ```js 197 | var total = reduce(add, 0, numbers); 198 | var sentence = reduce(joinWord, '', words); 199 | ``` 200 | 201 | Assim como `forEach` e `map`, `reduce` também é nativa no padrão JavaScript como um método do objeto Array. Podemos usá-la assim: 202 | 203 | ```js 204 | var total = numbers.reduce(add, 0); 205 | var sentence = words.reduce(joinWord, ''); 206 | ``` 207 | 208 | Você pode ler mais sobre o método nativo [`reduce` na referência JavaScript do MDN.](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce) 209 | 210 | ## Juntando Tudo 211 | Como mencionamos anteriormente, esses são exemplos triviais - as funções `add` e `joinWord` são muito simples - e esse é o ponto na verdade. Funções simples e pequenas são mais fáceis de pensar e testar. Mesmo quando pegamos duas funções pequenas e simples e as combinamos (como `add` e `reduce` por exemplo), o resultado ainda é mais fácil de se imaginar do que uma única função gigante e complicada. Mas, com isso dito, podemos fazer coisas mais interessantes do que adicionar números. 212 | 213 | Vamos tentar fazer algo um pouco mais complicado. Começaremos com dados formatados de forma não convencional, e usar as funções `map` e `reduce` para transformar isso em uma lista HTML. Aqui estão nossos dados: 214 | 215 | ```js 216 | var ponies = [ 217 | [ 218 | ['name', 'Fluttershy'], 219 | ['image', 'http://tinyurl.com/gpbnlf6'], 220 | ['description', 'Fluttershy is a female Pegasus pony and one of the main characters of My Little Pony Friendship is Magic.'] 221 | ], 222 | [ 223 | ['name', 'Applejack'], 224 | ['image', 'http://tinyurl.com/gkur8a6'], 225 | ['description', 'Applejack is a female Earth pony and one of the main characters of My Little Pony Friendship is Magic.'] 226 | ], 227 | [ 228 | ['name', 'Twilight Sparkle'], 229 | ['image', 'http://tinyurl.com/hj877vs'], 230 | ['description', 'Twilight Sparkle is the primary main character of My Little Pony Friendship is Magic.'] 231 | ] 232 | ]; 233 | ``` 234 | 235 | 236 | Os dados não estão muito arrumados. Seria muito mais claro se os arrays internos fossem objetos bem formatados. Previamente, nós usamos a função `reduce` para calcular simples valores como *strings* e números, mas ninguém disse que o valor retornado por `reduce` tem que ser simples. Nós podemos usar essa função com objetos, arrays ou até mesmo elementos DOM. Vamos criar uma função que recebe um desses arrays internos (como `['name', 'Fluttershy']`) e adiciona esse par chave/valor a um objeto. 237 | 238 | ```js 239 | var addToObject = function(obj, arr) { 240 | obj[arr[0]] = arr[1]; 241 | return obj; 242 | }; 243 | ``` 244 | 245 | Com essa função `addToObject` podemos converter cada "pequeno" array em um objeto: 246 | 247 | ```js 248 | var ponyArrayToObject = function(ponyArray) { 249 | return reduce(addToObject, {}, ponyArray); 250 | }; 251 | ``` 252 | 253 | Se usarmos nossa função `map` poderemos converter todo o array em algo mais arrumado: 254 | 255 | ```js 256 | var tidyPonies = map(ponyArrayToObject, ponies); 257 | ``` 258 | 259 | Agora temos um array de pequenos objetos. Com uma ajuda do [pequeno *template engine* de Thomas Fuchs](http://mir.aculo.us/2011/03/09/little-helpers-a-tweet-sized-javascript-templating-engine/), podemos usar `reduce` novamente para converter isso em um fragmento HTML. A *função template* pega uma string template e um objeto, e onde ela achar palavras envoltas com chaves (como `{name}` ou `{image}`), ela vai trocá-las com o valor correspondente no objeto. Por exemplo: 260 | 261 | ```js 262 | var data = { name: "Fluttershy" }; 263 | t("Hello {name}!", data); 264 | // "Hello Fluttershy!" 265 | 266 | data = { who: "Fluttershy", time: Date.now() }; 267 | t("Hello {name}! It's {time} ms since epoch.", data); 268 | // "Hello Fluttershy! It's 1454135887369 ms since epoch." 269 | ``` 270 | 271 | Então se quisermos converter um pequeno objeto em um item de uma lista, podemos fazer algo assim: 272 | 273 | ```js 274 | var ponyToListItem = function(pony) { 275 | var template = '
  • {name}' + 276 | '

    {name}

    {description}

    ' + 277 | '
  • '; 278 | return t(template, pony); 279 | }; 280 | ``` 281 | 282 | Isso nos dá uma forma de converter um item individual em HTML, mas para converter todo o array, precisaremos das nossas funções `reduce` e `joinWords`: 283 | 284 | ```js 285 | var ponyList = map(ponyToListItem, tidyPonies); 286 | var html = '
      ' + reduce(joinWord, '', ponyList) + '
    '; 287 | ``` 288 | 289 | Você pode ver o resultado final [aqui](http://jsbin.com/wuzini/edit?html,js,output) 290 | 291 | Uma vez que você entenda os padrões onde `map` e `reduce` são adequados, você não vai mais precisar de escrever um loop `for` da maneira antiga. De fato, é um desafio útil ver se você consegue evitar completamente a escrita de loops `for` no seu próximo projeto. Depois que você usar `map` e `reduce` algumas vezes, você vai começar a notar ainda mais padrões que podem ser abstraídos. Alguns comuns incluem *[filtrar](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)* e *[arrancar](http://ramdajs.com/docs/#pluck)* valores de um array. Uma vez que esses padrões aparecem regularmente, algumas pessoas criaram bibliotecas de programação funcional, assim você pode reutilizar código para solucionar padrões comuns. Algumas das bibliotecas mais populares são: 292 | 293 | - [Ramda](http://ramdajs.com/), 294 | - [Lodash](https://lodash.com/), e 295 | - [Underscore](http://underscorejs.org/). 296 | 297 | Agora que você viu quão útil é passar funções como variáveis, especialmente quando estamos lidando com listas, você deve ter um grande novo conjunto de técnicas no seu cinto de utildades metafórico. E se você escolher ir embora agora, está tudo bem. Você pode finalizar a leitura e ninguém vai pensar nada de ruim sobre você. Você pode ir e ser um programador bem sucedido e produtivo, e nunca perturbar seus sonhos com as complexidades da *partial application* (aplicação parcial), *currying* e *composition* (composição). Essas coisas não são para todo mundo. 298 | 299 | Mas, se você estiver afim de um pouco de aventura, [você pode continuar lendo e ver quão fundo a toca do coelho vai...](011-uma-suave-introducao-ao-javascript-parte-3.md) 300 | -------------------------------------------------------------------------------- /nodejs/001-guia-para-iniciantes-absolutos-em-nodejs.md: -------------------------------------------------------------------------------- 1 | # Guia Para Absolutos Iniciantes em Node.js 2 | 3 | ![node-baby](../img/node-absolute-begginer.png) 4 | 5 | * **Artigo Original**: [AN ABSOLUTE BEGINNER'S GUIDE TO NODE.JS](http://blog.modulus.io/absolute-beginners-guide-to-nodejs) 6 | * **Tradução**: [Eric Douglas](https://github.com/ericdouglas) 7 | 8 | > Veja uma versão atualizada desse artigo [aqui](https://github.com/ericdouglas/traduz-ai/blob/master/nodejs/-atualizado-simples-guia-nodejs-jade-express-mongodb.md) 9 | 10 | Não existe uma escassez de tutoriais para Node.js, mas a maioria deles cobrem casos de uso específicos ou tópicos que são aplicáveis só se você já tiver um conhecimento prático do Node. Eu vejo vários comentários que se parecem com coisas do tipo: "Eu fiz o download do node, agora o que fazer?" Este tutorial responde esta questão e explica como iniciar bem do princípio. 11 | 12 | ## O que é Node.js? 13 | 14 | Muitos iniciantes em Node tem a dúvida de o quê exatamente ele é, e a descrição em [nodejs.org](http://nodejs.org/) definitivamente não ajuda. 15 | 16 | Uma coisa importante de se perceber é que o Node não é um servidor web. Por ele próprio, não se tem nada. Ele não funciona como o Apache. Não existe um arquivo de configuração onde você o aponta para seus arquivos html. Se você quer que o Node seja um servidor HTTP, você tem que escrever um servidor HTTP (com a ajuda das bibliotecas incluídas). O Node.js é somente outra forma de executar código em seu computador. Ele é simplesmente um *JavaScript runtime* (ambiente de execução de código JavaScript). 17 | 18 | ## Instalando o Node.js 19 | 20 | Node.js é muito simples de ser instalado. Se você estiver usando Windows ou Mac, os instaladores estão disponíveis na [página de download](http://nodejs.org/download). 21 | 22 | ## Já tenho o Node instalado, e agora o que fazer? 23 | 24 | Uma vez instalado, agora você tem acesso a um novo comando chamado `node`. Você pode usar o comando `node` de duas formas diferentes. A primeira é sem argumentos. Isto irá abrir um shell interativo (REPL: read-eval-print-loop), onde você pode executar código JavaScript puro. 25 | 26 | ```sh 27 | 28 | $ node 29 | > console.log('Hello World'); 30 | Hello World 31 | undefined 32 | 33 | ``` 34 | 35 | No exemplo acima eu digitei `console.log('Hello World')` dentro do shell e apertei enter. O Node vai então executar o código e nós podemos ver nossa mensagem registrada. Ele também imprime `undefined` pelo fato de sempre mostrar o valor de retorno de cada comando, e `console.log` não retorna nada. 36 | 37 | A outra forma de rodar o Node é fornecendo a ele um arquivo JavaScript para execução. Isto será na maioria das vezes a maneira como você irá utilizá-lo. 38 | 39 | `hello.js` 40 | 41 | ```js 42 | 43 | console.log('Hello World'); 44 | 45 | ``` 46 | 47 | ```sh 48 | 49 | $ node hello.js 50 | Hello World 51 | 52 | ``` 53 | 54 | Neste exemplo, eu movi o comando `console.log()` para dentro de um arquivo e então passei este arquivo para o comando node como um argumento. O Node então roda o JavaScript contido neste arquivo e imprime "Hello World". 55 | 56 | ## Fazendo Algo Útil 57 | 58 | Rodar código JavaScript é divertido e tal, mas não é muito útil. Ai é onde o Node.js também inclui um poderoso conjunto de [bibliotecas](http://nodejs.org/api/) (módulos) para se fazer coisas reais. No primeiro exemplo eu vou abrir um arquivo de registros e analisá-lo. 59 | 60 | `example-log.txt` 61 | ``` 62 | 63 | 2013-08-09T13:50:33.166Z A 2 64 | 2013-08-09T13:51:33.166Z B 1 65 | 2013-08-09T13:52:33.166Z C 6 66 | 2013-08-09T13:53:33.166Z B 8 67 | 2013-08-09T13:54:33.166Z B 5 68 | 69 | ``` 70 | 71 | O que esses dados registrados significam não importa, mas basicamente cada mensagem contém uma data, uma letra e um valor. Eu quero somar os valores para cada letra. 72 | 73 | A primeira coisa que nós precisamos fazer é ler o conteúdo do arquivo. 74 | 75 | `my-parser.js` 76 | ```js 77 | 78 | // Carregando o módulo fs (filesystem) 79 | var fs = require('fs'); 80 | 81 | // Leia o conteúdo do arquivo para a memória 82 | fs.readFile('example-log.txt', function ( err, logData ) { 83 | 84 | // Se um erro ocorrer, será lançada uma 85 | // exceção, e a aplicação irá ser encerrada 86 | if ( err ) throw err; 87 | 88 | // logData é um Buffer, converta-o para string 89 | var text = logData.toString(); 90 | }); 91 | 92 | ``` 93 | 94 | Felizmente o Node.js faz a entrada e saída (I/O) do arquivo facilmente com o módulo embutido [filesystem](http://nodejs.org/api/fs.html) (`fs`). O módulo `fs` tem uma função chamada [readFile](http://nodejs.org/api/fs.html#fs_fs_readfile_filename_options_callback) que pega o caminho de um arquivo e um callback. O callback vai ser invocado quando o arquivo for lido por completo. O dado do arquivo vem na forma de um [Buffer](http://nodejs.org/api/buffer.html), que é basicamente um array de bytes. Nós podemos convertê-lo para uma string usando a função [`toString()`](http://nodejs.org/api/buffer.html#buffer_buf_tostring_encoding_start_end). 95 | 96 | Agora vamos adicionar o *parsing* (analisador). 97 | 98 | `my-parser.js` 99 | ```js 100 | 101 | // Carregando o módulo fs (filesystem) 102 | var fs = require('fs'); 103 | 104 | // Leia o conteúdo do arquivo para a memória 105 | fs.readFile('example-log.txt', function ( err, logData ) { 106 | 107 | // Se um erro ocorrer, será lançada uma 108 | // exceção, e a aplicação irá ser encerrada 109 | if ( err ) throw err; 110 | 111 | // logData é um Buffer, converta para string 112 | var text = logData.toString(); 113 | 114 | var results = {}; 115 | 116 | // Quebrando o arquivo em linhas 117 | var lines = text.split( '\n' ); 118 | 119 | lines.forEach(function ( line ) { 120 | var parts = line.split( ' ' ); 121 | var letter = parts[ 1 ]; 122 | var count = parseInt( parts[ 2 ] ); 123 | 124 | if ( !results[ letter ] ) { 125 | results[ letter ] = 0; 126 | } 127 | 128 | results[ letter ] += parseInt( count ); 129 | }); 130 | 131 | console.log( results ); 132 | // { A: 2, B: 14, C: 6 } 133 | }); 134 | 135 | ``` 136 | 137 | Agora vamos passar este arquivo como um argumento para o comando `node` e ele vai imprimir o resultado e sair. 138 | 139 | ```sh 140 | 141 | $ node my-parser.js 142 | { A: 2, B: 14, C: 6 } 143 | 144 | ``` 145 | 146 | Eu uso muito o Node.js para scripts como este. É uma alternativa muito mais simples e poderosa que os scripts bash. 147 | 148 | ## Callbacks Assíncronos 149 | 150 | Como você viu no exemplo anterior, o padrão típico do Node.js é o uso de callbacks assíncronos. Basicamente você está dizendo a ele para fazer algo e quando isso estiver terminado ele irá chamar sua função (callback). Isto porque o Node é de *thread* única. Enquanto você está esperando pelo disparo do callback, o Node pode fazer outras coisas ao invés de bloquear até que a requisição esteja terminada. 151 | 152 | Isso é especialmente importante para servidores web. Isto é muito comum em aplicações web modernas para acessar banco de dados. Enquanto você espera pelo retorno do banco de dados, o Node pode processar mais requisições. Isso permite que você manipule milhares de conexões conjuntas com pequenos acréscimos, comparado a criar uma thread separada para cada conexão. 153 | 154 | ## Fazendo Algo Útil - Servidor HTTP 155 | 156 | Como disse anteriormente, o Node não faz nada por si só. Um dos módulos embutidos tornam a criação de [servidores HTTP](http://nodejs.org/api/http.html#http_http_createserver_requestlistener) simples muito fácil, que é o [exemplo na página inicial do Node.js](http://nodejs.org/). 157 | 158 | `my-web-server.js` 159 | ```js 160 | 161 | var http = require('http'); 162 | 163 | http.createServer(function ( req, res ) { // req = requisição, res = resposta 164 | 165 | res.writeHead( 200, { 'Content-Type': 'text/plain' } ); 166 | res.end( 'Hello World\n' ); 167 | }).listen( 8080 ); 168 | 169 | console.log( 'Servidor rodando na porta 8080' ); 170 | 171 | ``` 172 | 173 | Quando eu digo básico, quero dizer básico mesmo. Este não é um servidor HTTP completo. Ele não pode servir qualquer arquivo HTML ou de imagem. De fato, não importa sua requisição, ela vai retornar 'Hello World'. No entanto, você pode rodar isto e verá em seu navegador no endereço `http://localhost:8080` o texto "Hello World". 174 | 175 | ```sh 176 | 177 | $ node my-web-server.js 178 | 179 | ``` 180 | 181 | Você pode ter percebido uma coisa diferente agora. Sua aplicação node.js não fechou. Isto acontece pois você criou um servidor e sua aplicação node vai continuar rodando e respondendo as requisições até que você mesmo mate o processo. 182 | 183 | Se você quiser ter um servidor web completo, você terá que fazer este trabalho. Você deve checar o que foi requisitado, ler os arquivos apropriados e enviar o conteúdo de volta. Pessoas já fizeram este trabalho duro para você. 184 | 185 | ## Fazendo Algo Útil - Express 186 | 187 | [Express](http://expressjs.com/) é um framework que torna a criação de sites normais muito simples. A primeira coisa que você tem que fazer é instalá-lo. Juntamente com o comando `node`, você também tem acesso a um comando chamado `npm`. Esta ferramenta permite que você acesse uma enorme coleção de módulos criados pela comunidade, e um deles é o Express. 188 | 189 | ```sh 190 | 191 | $ cd /my/app/location 192 | $ npm install express 193 | 194 | ``` 195 | 196 | Quando você instala um módulo, ele vai ser colado em uma pasta chamada *node_modules* dentro do diretório da sua aplicação. Você pode agora requisitar (*require*) este módulo como um módulo embutido. Vamos criar um arquivo estático básico usando o Express. 197 | 198 | `my-static-file-server.js` 199 | ```js 200 | 201 | var express = require('express'); 202 | app = express(); 203 | 204 | app.use(express.static(__dirname + '/public')); 205 | 206 | app.listen(8080); 207 | 208 | ``` 209 | ```sh 210 | 211 | $ node my-static-file-server.js 212 | 213 | ``` 214 | 215 | Agora você tem um servidor de arquivos estáticos bastante eficiente. Tudo que você colocar dentro da pasta `/public` poderá ser requisitado pelo seu navegador e será mostrado. HTML, imagens, enfim, tudo. Por exemplo, se você colocar uma imagem chamada `my-image.png` dentro da pasta `public`, você pode acessá-la usando seu navegador no endereço `http://localhost:8080/my-image.png`. Claro que o Express tem vários outros recursos, mas você pode olhá-los a medida que continua desenvolvendo. 216 | 217 | ## NPM 218 | 219 | Nós usamos um pouco o [NPM](https://npmjs.org/) nas seções anteriores, mas eu quero enfatizar o quão importante esta ferramenta se faz no desenvolvimento para Node.js. Existem milhares de módulos disponíveis que resolvem quase todos os problemas típicos que você encontra. Lembre-se de checar o NPM antes de re-inventar a roda. Não é inédito para uma aplicação Node ter dezenas de dependências. 220 | 221 | No exemplo anterior nós instalamos o Express manualmente. Se você tiver muitas dependências, essa não será uma forma muito interessante de instalá-las. É por isso que o NPM faz uso do arquivo `package.json`. 222 | 223 | `package.json`. 224 | ```js 225 | 226 | { 227 | "name" : "MyStaticServer", 228 | "version" : "0.0.1", 229 | "dependencies" : { 230 | "express" : "3.3.x" 231 | } 232 | } 233 | 234 | ``` 235 | 236 | Um arquivo [`package.json`](https://npmjs.org/doc/files/package.json.html) contém um resumo da sua aplicação. Existem vários campos disponíveis, sendo este apenas o mínimo. A seção *dependencies* (dependências) descreve o nome e a versão dos módulos que você gostaria de instalar. Neste caso eu vou aceitar qualquer versão do Express 3.3. Você pode listar quantas dependências quiser nesta seção. 237 | 238 | Agora, ao invés de instalar cada dependência em separado, nós podemos rodar um simples comando e instalar todas elas. 239 | 240 | ```sh 241 | 242 | $ npm install 243 | 244 | ``` 245 | 246 | Quando você roda este comando, o npm vai verificar na pasta atual pelo arquivo `package.json`. Se ele encontrar um, então irá instalar cada dependência listada. 247 | 248 | ## Organização do Código 249 | 250 | Até agora só usamos um único arquivo, que não é muito sustentável. Na maioria das aplicações, seu código vai ser dividido em vários arquivos. Não existe nenhuma norma ou organização imposta dizendo para onde os arquivos vão. Isto não é Rails. Não há conceitos de views e controllers acontecendo aqui. Você pode fazer o que quiser. 251 | 252 | Vamos refatorar o script de análise de registros (log parsing). Ele será muito mais testável e manutenível se nós separarmos a lógica de análise (parsing) dentro de um arquivo próprio. 253 | 254 | `parser.js` 255 | ```js 256 | 257 | // Construtor Parser 258 | var Parser = function () { 259 | 260 | }; 261 | 262 | // Analisa o texto especificado 263 | Parser.prototype.parse = function ( text ) { 264 | 265 | var results = {}; 266 | 267 | // Quebra o arquivo em linhas 268 | var lines = text.split('\n'); 269 | 270 | lines.forEach(function ( line ) { 271 | var parts = line.split( ' ' ); 272 | var letter = parts[ 1 ]; 273 | var count = parseInt( parts[2] ); 274 | 275 | if ( !results[ letter ] ) { 276 | results[ letter ] = 0; 277 | } 278 | 279 | results[ letter ] += parseInt( count ); 280 | }); 281 | 282 | return results; 283 | }; 284 | 285 | // Exportando o construtor Parser neste módulo 286 | module.exports = Parser; 287 | 288 | ``` 289 | 290 | O que eu fiz foi criar um novo arquivo para conter a lógica da análise dos registros. Isto é apenas JavaScript puro e existe várias formas de se encapsular este código. Eu escolhi por definir um novo objeto JavaScript pois assim é mais fácil de se fazer testes unitários. 291 | 292 | A parte importante para isso é a linha `module.exports`. Isso diz ao Node que você está exportando deste arquivo. Neste caso exportei um construtor, então os usuários podem criar instâncias do meu objeto `Parser`. Você pode exportar qualquer coisa que quiser. 293 | 294 | Agora vamos ver como importar este arquivo e fazer uso do novo objeto `Parser`. 295 | 296 | `my-parser.js` 297 | ```js 298 | 299 | // Requisitando o arquivo parser.js 300 | var Parser = require('./parser'); 301 | 302 | // Carregandoo módulo fs (filesystem) 303 | var fs = require('fs'); 304 | 305 | // Lendo o conteúdo do arquivo para a memória 306 | fs.readFile('example-log.txt', function ( err, logData ) { 307 | 308 | // Se um erro ocorrer, irá ser lançada 309 | // a exceção e a app será encerrada 310 | if ( err ) throw err; 311 | 312 | // logData é um Buffer, converta-o para string 313 | var text = logData.toString(); 314 | 315 | // Criando uma instância do objeto Parser 316 | var parser = new Parser(); 317 | 318 | // Chame a função parse 319 | console.log( parser.parse( text ) ); 320 | // { A: 2, B: 14, C: 6 } 321 | }); 322 | 323 | ``` 324 | 325 | Arquivos são incluídos da mesma forma que os módulos, exceto que você inclui um caminho ao invés de um nome. A extensão `.js` é implícita, então você pode omití-la se quiser. 326 | 327 | Tendo sido exportado um construtor, é isso que vai ser retornado da declaração `require`. Eu posso agora criar instâncias do meu objeto `Parser` e usá-las. 328 | 329 | ## Resumo 330 | 331 | Esperamos que este tutorial tenha feito a ponte entre a parte de fazer o download do Node.js e construir sua primeira ferramenta. O Node.js é uma tecnologia extremamenta poderosa e flexível que pode resolver uma vastidão de tipos de problemas. 332 | 333 | Eu quero que cada um de vocês se lembre que o Node.js é somente limitado pela sua imaginação. As bibliotecas de seu núcleo foram cuidadosamente projetadas para fornecer as peças do quebra-cabeça necessárias para se construir qualquer fotografia. Combine-as com módulos disponíveis no NPM e será incrível o quão rápido você poderá começar a construir aplicações muito complexas e atraentes. 334 | -------------------------------------------------------------------------------- /javascript/012-uma-suave-introducao-ao-javascript-parte-4.md: -------------------------------------------------------------------------------- 1 | # Uma Suave Introdução ao JavaScript Funcional: Parte 4 2 | 3 | * **Artigo Original**: [A GENTLE INTRODUCTION TO FUNCTIONAL JAVASCRIPT: PART 4](http://jrsinclair.com/articles/2016/gentle-introduction-to-functional-javascript-style/) 4 | * **Tradução**: [Eric Douglas](https://github.com/ericdouglas) 5 | 6 | > *Escrito por James Sinclair em 11 de Fevereiro de 2016* 7 | 8 | Essa é a parte 4 de uma série de 4 artigos sobre introdução a programação funcional no JavaScript. No último artigo vamos ver sobre *high-order functions* (funções de ordem superior): funções para criar funções. Nesse artigo, nós discutimos como usar essas novas ferramentas com estilo. 9 | 10 | - [Parte 1: Blocos fundamentais e motivação](009-uma-suave-introducao-ao-javascript-parte-1.md) 11 | - [Parte 2: Trabalhando com Arrays e Listas](010-uma-suave-introducao-ao-javascript-parte-2.md) 12 | - [Parte 3: Funções para fazer funções](011-uma-suave-introducao-ao-javascript-parte-3.md) 13 | - Parte 4: Fazendo isso com estilo (esse artigo) 14 | 15 | ## Fazendo Isso Com Estilo 16 | No artigo anterior vimos sobre `partial`, `compose`, `curry`, `pipe`, e também como podemos usá-las para juntar pequenas, simples funções e criar outras grandes e complicadas. Mas o que isso faz pra gente? Vale a pena se importar quando já estamos escrevendo código perfeitamente válido? 17 | 18 | Parte da resposta é que sempre é útil ter mais ferramentas disponíveis para realizar o trabalho - desde que você saiba como usá-las - e programação funcional certamente nos dá um conjunto útil de ferramentas para escrever JavaScript. Mas eu penso que há mais do que isso. Programação Funcional nos abre um diferente *estilo* de programação. Isso por sua vez nos permite conceitualizar problemas e soluções de formas diferentes. 19 | 20 | Existem duas funcionalidades chave para programação funcional: 21 | 22 | 1. Escrever funções puras, o que é importante se você deseja testar programação funcional; e 23 | 1. Estilo de programação *pointfree* (sem pontos), o que não é *tão* importante mas é bom de se entender. 24 | 25 | ### Pureza 26 | Se você ler sobre programação funcional, você irá se deparar com o conceito de funções *puras* e *impuras*. Funções puras são funções que preenchem dois critérios: 27 | 28 | 1. Chamar a função com as mesmas entradas sempre *retorna* as mesmas saídas. 29 | 1. Chamar a função não produz efeitos colaterais: Sem chamadas na rede (*network*); nenhuma leitura ou escrita de arquivos; nenhuma consulta em banco de dados; nenhum elemento DOM modificado; nenhuma modificação de variáveis globais; e nenhuma saída no console. Nada. 30 | 31 | Funções impuras deixam programadores funcionais desconfortáveis. Tão desconfortáveis que eles as evitam o máximo possível. O problema com isso é que o grande ponto de escrever programas de computador *são* os efeitos colaterais. Fazer uma chamada na rede e renderizar elementos DOM está no núcleo do que uma aplicação web faz; esse foi o motivo pelo qual o JavaScript foi inventado. 32 | 33 | Então o que um aspirante a programador funcional faz? Bom, a chave é que nós não evitamos funções impuras inteiramente, nós apenas damos a elas uma boa quantidade de respeito, e deixamos de lidar com elas até que nós absolutamente precisemos. Elaboramos um plano claro e testado para o que queremos fazer *antes* de tentar fazer isso. Como Eric Elliot colocou em [*The Dao of Immutability*](https://medium.com/javascript-scene/the-dao-of-immutability-9f91a70c88cd): 34 | 35 | > **Separação:** Lógica é pensamento. Efeitos são ações. Portanto, o sábio pensa antes de agir, e age somente quando o pensamento está terminado. Se você tentar executar efeitos e lógica ao mesmo tempo, você vai criar efeitos colaterais ocultos que causam *bugs* (problemas) na lógica. Mantenha as funções pequenas. Faça uma coisa de cada vez, e faça isso bem. 36 | 37 | Em outras palavras, com programação funcional, nós geralmente trabalhamos a lógica do que estamos tentando fazer primeiro, antes de fazer qualquer coisa que potencialmente tenha efeitos colaterais. 38 | 39 | Outra forma de pensar sobre isso é a diferença de usar uma metralhadora e um *rifle sniper*. Com a metralhadora você dispara o máximo de balas possível, contando com o fato que se você continuar atirando, eventualmente você vai acertar algo. Mas você pode também acertar coisas que você não queria. Porém um rifle sniper é direfente. Você escolhe o lugar mais vantajoso, alinha o tiro, toma em conta a velocidade do vento e a distância do alvo. Você pacientemente, metodicamente, cuidadosamente configura todas as coisas e no momento certo, puxa o gatilho. Muito menos munição, e um efeito muito mais preciso. 40 | 41 | Então como tornamos nossas funções puras? Vamos ver um exemplo: 42 | 43 | ```js 44 | var myGlobalMessage = '{{verb}} me'; 45 | 46 | var impureInstruction = function(verb) { 47 | return myGlobalMessage.replace('{{verb}}', verb); 48 | } 49 | 50 | var eatMe = impureInstruction('Eat'); 51 | //=> 'Eat me' 52 | var drinkMe = impureInstruction('Drink'); 53 | //=> 'Drink me' 54 | ``` 55 | 56 | Essa função é impura pois depende da variável global `myGlobalMessage`. Se a variável mudar, se torna difícil dizer o que `impureInstruction` vai fazer. Uma forma de torná-la pura é mover a variável para dentro: 57 | 58 | ```js 59 | var pureInstruction = function (verb) { 60 | var message = '{{verb}} me'; 61 | return message.replace('{{verb}}', verb); 62 | } 63 | ``` 64 | 65 | Essa função agora vai sempre retornar o mesmo resultado dado um mesmo conjunto de entradas. Mas algumas vezes não podemos usar essa ténica. Por exemplo: 66 | 67 | ```js 68 | var getHTMLImpure = function(id) { 69 | var el = document.getElementById(id); 70 | return el.innerHTML; 71 | } 72 | ``` 73 | 74 | Essa função é impura pois depende do objeto `document` para acessar o DOM. Se o DOM mudar isso *pode* produzir resultados diferentes. Mas nós não podemos definir `document` dentro de nossa função porque isso é uma API do navegador, mas nós *podemos* passar isso como um parâmetro: 75 | 76 | ```js 77 | var getHTML = function(doc, id) { 78 | var el = doc.getElementById(id); 79 | return el.innerHTML; 80 | } 81 | ``` 82 | 83 | Isso pode parecer trivial e sem sentido, mas é uma técnica útil. Imagine você estava tentando fazer um teste unitário nessa função. Normalmente, teríamos que configurar algum tipo de browser para pegar o objeto `document` e poder testar isso. Uma vez que temos o parâmetro `doc`, é fácil passar um objeto *stub* - uma simulação do objeto real - ao invés disso: 84 | 85 | ```js 86 | var stubDoc = { 87 | getElementById: function(id) { 88 | if (id === 'jabberwocky') { 89 | return { 90 | innerHTML: '

    Twas brillig…' 91 | }; 92 | } 93 | } 94 | }; 95 | 96 | assert.equal(getHTML('jabberwocky'), '

    Twas brillig…'); 97 | //=> test passes 98 | ``` 99 | 100 | Escrever esse *stub* pode parecer um pouco trabalhoso, mas agora podemos testar essa função sem precisar de um navegador. Se quisermos, podemos rodar isso na linha de comando sem um navegador *headless*. E como um bônus, o teste vai rodar muito, muito mais rápido do que um que tenha o objeto `document` inteiro. 101 | 102 | Uma outra forma de ter uma função pura é retornar outra função que eventualmente irá fazer algo impuro quando a chamarmos. Isso inicialmente parece um truque sujo, mas é totalmente legítimo. Por exemplo: 103 | 104 | ```js 105 | var htmlGetter = function(id) { 106 | return function() { 107 | var el = document.getElementById(id); 108 | return el.innerHTML; 109 | } 110 | } 111 | ``` 112 | 113 | A função `htmlGetter` é pura porque rodando-a não acessamos uma variável global - ao invés disso, ela sempre retorna exatamente a mesma função. 114 | 115 | Fazer coisas dessa forma não é muito útil para testes unitários, e isso não remove a impureza completamente - apenas a posterga. E isso não é necessariamente uma coisa ruim. Lembre-se, queremos lidar com toda a lógica previamente nas funções puras e depois puxar o gatilho em quaisquer efeitos colaterais. 116 | 117 | ### *Pointfree* (sem pontos) 118 | Programação *Pointfree* ou programação *tácita* é um estilo particular de programação que funções de ordem superior como `curry` e `compose` tornam possível. Para explicar isso, vamos olhar novamente para o exemplo do poema do último artigo: 119 | 120 | > **Nota do tradutor:** Programação tácita, também chamada estilo **point-free** (sem pontos), é um paradigma de programação em que definições de função não identificam os argumentos (ou "pontos") em que elas operam. Ao invés disso, as definições meramente compõem outras funções, onde essas são combinadores que manipulam os argumentos. [Fonte](https://en.wikipedia.org/wiki/Tacit_programming). 121 | 122 | ```js 123 | var poem = 'Twas brillig, and the slithy toves\n' + 124 | 'Did gyre and gimble in the wabe;\n' + 125 | 'All mimsy were the borogoves,\n' + 126 | 'And the mome raths outgrabe.'; 127 | 128 | var replace = curry(function(find, replacement, str) { 129 | var regex = new RegExp(find, 'g'); 130 | return str.replace(regex, replacement); 131 | }); 132 | 133 | var wrapWith = curry(function(tag, str) { 134 | return '<' + tag + '>' + str + ''; 135 | }); 136 | 137 | var addBreaks = replace('\n', '
    \n'); 138 | var replaceBrillig = replace('brillig', wrapWith('em', 'four o’clock in the afternoon')); 139 | var wrapP = wrapWith('p'); 140 | var wrapBlockquote = wrapWith('blockquote'); 141 | 142 | var modifyPoem = compose(wrapBlockquote, wrapP, addBreaks, replaceBrillig); 143 | ``` 144 | 145 | Note que `compose` espera que cada função passada receba exatamente um parâmetro. Então, usamos 'curry' para mudar nossas funções multi-parâmetros `replace` e `wrapWith` em funções de um único parâmetro. Note também que fomos um pouco criteriosos com a ordem de nossas funções, então `wrapWith`, por exemplo, recebe a *tag* como seu primeiro parâmetro ao invés do texto para ser envolvido. Se formos cuidadosos dessa forma na maneira como configuramos nossas funções, isso fará a criação de funções por composição fácil. 146 | 147 | > **Nota do autor**: A maioria das bibliotecas funcionais (como [Ramda](http://ramdajs.com/)), também incluem utilitários para trabalhar com funções que não tem seus parâmetros em uma ordem conveniente. 148 | 149 | Isso se torna tão fácil que você pode escrever *todo* o seu código dessa maneira. Mas note um pequeno efeito colateral: quando definimos a função `modifyPoem` final, nós nunca mencionamos em nenhum lugar que ela recebe um único argumento *string*. E se você olhar para as funções *curried*, `addBreaks`, `replaceBrillig`, `wrapP` e `wrapBlockquote`, nenhuma delas mencionam que recebem também apenas uma simples variável *string*. Isso é programação *pointfree* (sem pontos): começar com um conjunto base de funções utilitárias (como Ramda ou functional.js) e escrever seu código de uma forma que você nunca vai mencionar as variáveis de entrada. 150 | 151 | O que isso nos dá? Bom, nada de especial em relação ao próprio código. A coisa inteligente sobre o estilo sem pontos é que ele te força a usar `compose`, `curry`, `pipe`, etc. Por sua vez, isso *encoraja fortemente* que você mantenha funções pequenas e simples reunidas de maneira sensata. Em outras palavras, isso é uma limitação autoimposta, como um *haiku* ou um soneto. Nem toda poesia tem que ser escrita dessa forma - e seguir todas as regras não garante um belo poema - mas algumas poesias escritas nesses estilos podem ser incrivelmente belas. 152 | 153 | Fazer tudo no estilo sem pontos não é sempre prático. Algumas vezes, isso adiciona complicações desnecessárias em uma função simples. Mas dar uma chance e *tentar* escrever todas as suas funções sem pontos é uma boa maneira de entender melhor a programação funcional. 154 | 155 | ### Assinatura de Tipos de Hindley-Milner 156 | Uma vez que você esteja fazendo tudo "sem pontos" (*pointfree*), isso deixa uma dúvida, como comunicar outros programadores qual tipo de parâmetro eles devem passar para sua função. Para facilitar isso, programadores funcionais desenvolveram uma notação especial para especificar quais tipos de parâmetro uma função recebe, e o que ela retorna. A notação é chamada *assinatura de tipos de Hindley-Milner*. Nós a escrevemos como comentários onde definimos a função. Vamos ver alguns exemplos: 157 | 158 | ```js 159 | // instruction :: String -> String 160 | var instruction = function(verb) { 161 | return verb + ' me'; 162 | } 163 | ``` 164 | 165 | A assinatura de tipo diz que `instruction` recebe uma *String* como entrada e retorna outra *String*. Por enquanto, tudo bem. E se tivermos uma função que recebe dois parâmetros? 166 | 167 | ```js 168 | // wrapWith :: String -> (String -> String) 169 | var wrapWith = curry(function(tag, str) { 170 | return '<' + tag + '>' + str + ''; 171 | }); 172 | ``` 173 | 174 | Isso é um pouco mais complicado, mas não tão difícil. Essa notação diz que `wrapWith` recebe uma *String* e retorna uma *Função*, e essa função recebe uma *String* e retorna uma *String*. Note que isso funciona porque nós aplicamos *curry* na função. Quando estivermos usando esse estilo, está assumido que você sempre vai usar *curry* em todas suas funções. 175 | 176 | E algo com três parâmetros ao invés de dois? Uma forma de escrever isso seria: 177 | 178 | ```js 179 | // replace :: String -> (String -> (String -> String)) 180 | var replace = curry(function(find, replacement, str) { 181 | var regex = new RegExp(find, 'g'); 182 | return str.replace(regex, replacement); 183 | }); 184 | ``` 185 | 186 | Agora temos uma função que retorna uma função que retorna uma função que retorna uma *string*. Isso ainda faz sentido, mas porque sempre assumimos que tudo está sendo *curried*, tendemos a remover os parênteses: 187 | 188 | ```js 189 | // replace :: String -> String -> String -> String 190 | ``` 191 | 192 | E se tivermos um parâmetro de um tipo diferente: 193 | 194 | ```js 195 | // formatDollars :: Number -> String 196 | var formatDollars = replace('${{number}}', '{{number}}'); 197 | 198 | formatDollars(100); 199 | //=> $100 200 | ``` 201 | 202 | Aqui temos uma função sem pontos (*pointfree*), e se torna claro porque as assinaturas de tipos são úteis. Essa pega um número e retorna uma *string*. E se tivéssemos um array? 203 | 204 | ```js 205 | // sum :: [Number] -> Number 206 | var sum = reduce(add, 0); 207 | ``` 208 | 209 | Essa recebe um array de números e retorna um número (assumindo que aplicamos *curry* na função `reduce` do segundo artigo). 210 | 211 | Alguns exemplos finais: 212 | 213 | ```js 214 | // identity :: a -> a 215 | var identity = function(x) { return x }; 216 | 217 | // map :: (a -> b) -> [a] -> [b] 218 | var map = curry(function(callback, array) { 219 | return array.map(callback); 220 | }); 221 | ``` 222 | 223 | A função `identity` acima recebe um parâmetro de um tipo e retorna uma variável do mesmo tipo. A função `map` por outro lado, recebe uma função que recebe uma variável do tipo *a* e retorna uma variável do tipo *b*. Depois então pega um array de valores, todos do tipo *a* e retorna um array de valores, todos do tipo *b*. 224 | 225 | Você verá que bibliotecas como [Ramda](http://ramdajs.com/), por exemplo, usam essa notação para documentar todas as funções da biblioteca. 226 | 227 | ### Indo Mais Fundo 228 | Nós mal arranhamos a superfície da programação funcional. Mas entendendo funções de primeira classe, aplicação parcial e composição nos dá os blocos básicos para irmos muito mais longe. Se você estiver interessado em ler mais, há uma lista de links úteis abaixo: 229 | 230 | - [Can Your Programming Language do This?](http://www.joelonsoftware.com/items/2006/08/01.html) by Joel Spolsky 231 | - [The Dao of Immutability](https://medium.com/javascript-scene/the-dao-of-immutability-9f91a70c88cd) by Eric Elliot 232 | - [Why Ramda?](http://fr.umio.us/why-ramda/), by Scott Sauyet 233 | - [Professor Frisby’s Mostly Adequate Guide to Functional Programming](https://github.com/MostlyAdequate/mostly-adequate-guide) by Brian Lonsdorf 234 | - [JavaScript Allongé](https://leanpub.com/javascriptallongesix/read) by Reg “raganwald” Braithwaite 235 | -------------------------------------------------------------------------------- /series/entao-voce-quer-ser-um-programador-funcional/parte-1.md: -------------------------------------------------------------------------------- 1 | # Então você quer ser um Programador Funcional? (Parte 1) 2 | 3 | * **Artigo original**: [So You Want to be a Functional Programmer (Part 1)](https://medium.com/@cscalfani/so-you-want-to-be-a-functional-programmer-part-1-1f15e387e536#.es7crd8y1) 4 | * **Tradução**: [Gabriel](https://github.com/gabriel-ribeiro-ir) 5 | 6 | Dar o primeiro passo para entender os conceitos de Programação Funcional é o mais importante e algumas vezes o passo mais díficil. Mas isto não tem de ser assim. Não com a perspectiva correta. 7 | 8 | ### Aprendendo a dirigir 9 | 10 | Quando acabamos de aprender a dirigir, nós fazemos um grande esforço. Parecia fácil quando víamos outras pessoas dirigindo. Mas acaba se tornando mais difícil do que pensamos. 11 | 12 | Nós praticamos no carro de nossos pais e não nos aventuramos pela rodovia até dominarmos as ruas de nossa vizinhança. 13 | 14 | Mas através de muita prática e alguns momentos de pânico que nossos pais gostariam de esquecer, nós aprendemos a dirigir e finalmente pegamos nossa habilitação. 15 | 16 | Com a habilitação em mãos, pegamos o carro em qualquer oportunidade que temos. Com cada viagem, nós melhoramos e nossa confiança aumenta. Então chega o dia em que temos que dirigir o carro de outra pessoa, ou o nosso finalmente entregou os pontos e temos que comprar um novo. 17 | 18 | Como foi aquela primeira vez atrás do volante de um **carro diferente**? Foi como a primeiríssima vez? Nem chega perto. Na primeira vez foi tudo tão estranho. Nós já estivemos em um carro antes disso, mas somente como passageiros. Desta vez nós estamos no assento do motorista. Os únicos com todos os controles. 19 | 20 | Mas quando dirigimos nosso segundo carro, simplesmente nos perguntamos algumas coisas simples como, onde vai a chave, onde estão os faróis, como usamos a seta e como ajustamos os retrovisores. 21 | 22 | Depois disto, dirigimos suavemente. Mas por que desta vez foi tão fácil comparada à primeira? 23 | 24 | Porque o novo carro é muito parecido com o antigo. Ele tinha todas as coisas básicas que um carro precisa e eles estavam praticamente no mesmo lugar. 25 | 26 | Algumas coisas foram implementadas de forma diferente e talvez tivesse algumas funcionalidades adicionais, mas nós não as usamos na primeira, ou mesmo na segunda vez que dirigimos. Eventualmente, nós aprendemos todas as novas funcionalidades. Pelo menos aquelas que nos importam. 27 | 28 | Bem, aprender linguagens de programação é parecido com isto. A primeira é a mais difícil. Mas uma vez que você tenha uma em seu cinturão, as subsequentes são mais fáceis. 29 | 30 | Quando você começa a segunda linguagem, você pergunta coisas como, "Como eu crio um módulo? Como faço uma busca em um array? Quais são os parâmetros da função substring?" 31 | 32 | Você está confiante que pode aprender esta nova linguagem porque ela te lembra a antiga, talvez com algumas coisas novas que esperançosamente farão sua vida mais fácil. 33 | 34 | ### Sua primeira Nave Espacial 35 | 36 | Se você tem dirigido um carro sua vida toda ou uma dúzia de carros, imagine que você está prestes a estar atrás do volante de uma nave espacial. 37 | 38 | Se você estivesse indo voar em uma nave espacial, não poderia esperar que sua habilidade na estrada ajudasse muito. Você estaria começando do zero. (Afinal somos todos programadores. Nós contamos a partir do zero.) 39 | 40 | Você começaria seu treinamento com a expectativa de que as coisas são bastante diferentes no espaço e que voar nesta geringonça é muito diferente que dirigir no chão. 41 | 42 | A física não mudou. Somente a maneira que você navega dentro do mesmo Universo. 43 | 44 | E é a mesma coisa com aprender Programação Funcional. Você deve esperar que as coisas serão um pouco diferentes. E muito do que você sabe sobre programação **não** será traduzível. 45 | 46 | Programação é pensar e Programação Funcional te ensinará a pensar diferente. Tanto que você provavelmente nunca mais voltará a pensar da mesma maneira. 47 | 48 | ### Esqueça tudo o que você sabe 49 | 50 | As pessoas amam dizer esta frase, mas é um pouco verdade. **Aprender programação funcional é como começar do zero**. Não completamente, mas efetivamente. Existem muitos conceitos similares mas é melhor esperar que você vai ter de re-aprender tudo. 51 | 52 | Com a perspectiva correta você terá as expectativas certas, e com as expectativas certas você não desistirá quando as coisas ficarem difíceis. 53 | 54 | Existem todos os tipos de coisas que você está acostumado a fazer como programador que não poderá mais fazer em Programação Funcional. 55 | 56 | Assim como no seu carro, você costumava dar a ré para sair da garagem. Mas em uma nave espacial não existe marcha a ré. Agora você pode pensar, "O QUÊ? SEM MARCHA A RÉ?! COMO DIABOS EU DEVERIA DIRIGIR SEM MARCHA A RÉ?!" 57 | 58 | Bem, acontece que você não precisa de marcha a ré em uma nave espacial por causa de sua habilidade de manobrar em um espaço tridimensional. Uma vez que você entenda isto, você nunca mais sentirá falta da marcha a ré outra vez. De fato, algum dia, você vai pensar em quanto limitado o carro realmente era. 59 | 60 | > Aprender Programação Funcional leva um tempo. Então seja paciente. 61 | 62 | Então vamos sair do mundo frio da Programação Imperativa e vamos dar um mergulho suave na fonte quentinha da Programação Funcional. 63 | 64 | O que se segue nesta série de artigos são Conceitos de Programação Funcional que ajudarão você antes de mergulhar na sua primeira Linguagem Funcional. Ou se você já mergulhou, vai te ajudar a compreender. 65 | 66 | Por favor não corra. Tome seu tempo de leitura deste ponto em diante e não tenha pressa para entender os exemplos de código. Você pode até mesmo parar de ler depois de cada seção para aprofundar as ideias, e então voltar depois para terminar. 67 | 68 | O que realmente importa é que você **entenda**. 69 | 70 | ### Pureza 71 | 72 | Quando Programadores Funcionais falam de Pureza, eles estão se referindo a Funções Puras. 73 | 74 | Funções Puras são funções simples. Elas somente operam em seus parâmetros de entrada. 75 | 76 | Aqui está um exemplo de Função Pura com Javascript: 77 | 78 | var z = 10; 79 | function add(x, y) { 80 | return x + y; 81 | } 82 | 83 | Note que a função **add** NÃO toca na variável z. Ela não lê nem escreve na variável **z**. Ela somente lê **x** e **y**, seus parâmetros, e retorna o resultado da adição deles. 84 | 85 | Isto é uma função pura. Se a função **add** tivesse acesso a **z**, não seria mais pura. 86 | 87 | Aqui está outra função para considerar: 88 | 89 | function justTen() { 90 | return 10; 91 | } 92 | 93 | Se a função **justTen** é pura, então ela pode somente retornar uma constante. Correto? 94 | 95 | Pelo motivo de não passarmos parâmetros para ela. E uma vez que, para ser pura, ela não pode acessar nada que não seja seus parâmetros, a única coisa que ela pode retornar é uma constante. 96 | 97 | Uma vez que funções puras que não recebem parâmetros não fazem nada, elas não são muito úteis. Seria melhor se **justTen** fosse definida como uma constante. 98 | 99 | > As Funções Puras mais úteis recebem pelo menos um parâmetro 100 | 101 | Considere esta função: 102 | 103 | function addNoReturn(x, y) { 104 | var z = x + y; 105 | } 106 | 107 | Perceba como esta função não retorna nada. Ela adiciona **x** e **y** e guarda na variável **z** mas não a retorna. 108 | 109 | É uma funçao pura, já que lida somente com seus parâmetros. Ela faz a adição, mas não retornando seu resultado, é inútil. 110 | 111 | > Toda função pura precisa retornar alguma coisa para ser **útil** 112 | 113 | Vamos considerar a primeira funçao **add** novamente: 114 | 115 | function add(x, y) { 116 | return x + y; 117 | } 118 | console.log(add(1, 2)); // imprime 3 119 | console.log(add(1, 2)); // ainda imprime 3 120 | console.log(add(1, 2)); // SEMPRE vai imprimir 3 121 | 122 | Observe que **add(1, 2)** é sempre **3**. Não é uma grande surpresa, mas somente porque a função é pura. Se a função **add** usasse algum valor externo, então você **nunca** poderia prever seu comportamento. 123 | 124 | > Funções puras **sempre** produzem a mesma saída dados os mesmos parâmetros. 125 | 126 | Visto que funções puras não podem mudar variáveis externas, todas as funções a seguir são **impuras**: 127 | 128 | writeFile(fileName); 129 | updateDatabaseTable(sqlCmd); 130 | sendAjaxRequest(ajaxRequest); 131 | openSocket(ipAddress); 132 | 133 | Todas estas funções tem o que é chamado de **Side Effects** (Efeitos colaterais). Quando você as chama, elas alteram arquivos e tabelas de banco de dados, enviam dados para um servidor ou pedem ao SO por um socket. Elas fazem mais do que somente operar em seus parâmetros de entrada e retornar uma saída. Portanto, você *nunca* pode prever o que estas funções retornam. 134 | 135 | > Funções puras **não possuem** side effects. 136 | 137 | Em linguagens de programação imperativas como Javascript, Java, e C#, os Side Effects estão por toda a parte. Isto torna o debugging mais díficil porque uma variável pode ser alterada em **qualquer lugar** do seu programa. Então quando você tem um bug por causa de uma variável que mudou para o valor errado na hora errada, onde você procura? Por toda a parte? Isto não é bom. 138 | 139 | Neste ponto você provavelmente está pensando, "COMO DIABOS EU FAÇO QUALQUER COISA **SOMENTE** COM FUNÇÕES PURAS?!" 140 | 141 | Em Programação Funcional você não só escreve Funções Puras. 142 | 143 | Linguagens Funcionais não podem eliminar os Side Effects, elas só podem confiná-los. Desde que os programas tem de interagir com o mundo real, algumas partes precisam ser impuras. O objetivo é minimizar a quantidade de código impuro e segregá-lo do resto do seu programa. 144 | 145 | ### Imutabilidade 146 | 147 | Você se lembra de quando viu o seguinte trecho de código: 148 | 149 | var x = 1; 150 | x = x + 1; 151 | 152 | E quem quer que esteve te ensinando falou para você esquecer o que você aprendeu em matemática? Na matemática, **x** nunca pode ser igual a **x + 1**. 153 | 154 | Mas em Programação Imperativa, isto significa: Pegue o valor atual de **x** e adicione **1** a ele e guarde o resultado de volta no **x**. 155 | 156 | Bem, em Programação Funcional, **x = x + 1** é ilegal. Então você deve **relembrar** o que você **esqueceu** da matemática... mais ou menos isto. 157 | 158 | > **Não** existem variáveis em Programação Funcional. 159 | 160 | Valores guardados ainda são chamados de variáveis por causa da história mas eles são constantes, por exemplo: Uma vez que **x** ganha um valor, será seu valor pela vida toda. 161 | 162 | Não se preocupe, **x** é uma variável local, então sua vida será curta. Mas enquanto estiver viva, ela nunca muda. 163 | 164 | Aqui está um exemplo de variáveis consantes em Elm, uma Linguagem Funcional Pura para Desenvolvimento Web: 165 | 166 | addOneToSum y z = 167 | let 168 | x = 1 169 | in 170 | x + y + z 171 | 172 | Se você não está acostumado com a sintaxe ML-Style, permita-me explicar. **addOneToSum** é uma função que recebe 2 parâmetros, **y** e **z**. 173 | 174 | Dentro do bloco **let** é atribuido a **x** o valor **1**, isto é, seu valor será igual a **1** pelo resto de sua vida. Sua vida acaba quando a função é encerrada ou mais precisamente quando o bloco **let** é avaliado. 175 | 176 | Dentro do bloco **in**, o cálculo pode incluir valores definidos no bloco **let**, vide **x**. O resultado do cálculo **x + y + z** é retornado, ou mais precisamente, **1 + y + z** é retornado já que **x = 1**. 177 | 178 | Novamente eu posso te ouvir perguntando "COMO DIABOS EU SUPOSTAMENTE FARIA ALGUMA COISA SEM VARIÁVEIS?!" 179 | 180 | Vamos pensar em quando nós queremos modificar variáveis. No geral, existem 2 casos que vem em mente: mudanças multi-valores (ex. mudando um único valor de um objeto ou registro) e mudanças de valor único (ex. contadores de loop). 181 | 182 | Programação Funcional lida com mudanças de valores em um registro fazendo uma cópia do registro com os valores alterados. Isto é feito eficientemente sem ter de copiar todas as partes do registro, usando estruturas de dados que torna isso possível. 183 | 184 | Programação funcional resolve mudanças de valor único exatamente da mesma forma, fazendo uma cópia dele. 185 | 186 | Oh, sim e **não** possuindo loops. 187 | 188 | "O QUÊ? SEM VARIÁVEIS E AGORA SEM LOOPS?! EU TE ODEIO!!!" 189 | 190 | Calma. Não é que não podemos fazer loops (sem trocadilhos), é só que não existem construtores específicos de loop como **for, while, do, repeat**, etc. 191 | 192 | > Programação Funcional usa recursão para fazer looping. 193 | 194 | Aqui estão duas maneiras de fazer loops em Javascript: 195 | 196 | // construtor de loop simples 197 | var acc = 0; 198 | for (var i = 1; i <= 10; ++i) 199 | acc += i; 200 | console.log(acc); // imprime 55 201 | 202 | // sem construtor de loop ou variáveis (recursão) 203 | function sumRange(start, end, acc) { 204 | if (start > end) 205 | return acc; 206 | return sumRange(start + 1, end, acc + start) 207 | } 208 | console.log(sumRange(1, 10, 0)); // imprime 55 209 | 210 | Perceba que a recursão, a abordagem funcional, realiza o mesmo que um loop **for** chamando a si mesma com um *novo* start (**start + 1**) e um *novo* acumulador (**acc + start**). Ela não modifica os valores antigos Ao invés disso usa novos valores calculados a partir dos antigos. 211 | 212 | Infelizmente, isto é díficil de ver no Javascript, mesmo que você gaste um tempinho estudando, por duas razões. Primeiro, a sintaxe do Javascript é espalhafatosa e segundo, provavelmente você não está acostumado a pensar recursivamente. 213 | 214 | No Elm, isto fica mais fácil de ler e por consequência fácil de entender. 215 | 216 | sumRange start end acc = 217 | if start > end then 218 | acc 219 | else 220 | sumRange (start + 1) end (acc + start) 221 | 222 | Aqui está como é executado: 223 | 224 | sumRange 1 10 0 = -- sumRange (1 + 1) 10 (0 + 1) 225 | sumRange 2 10 1 = -- sumRange (2 + 1) 10 (1 + 2) 226 | sumRange 3 10 3 = -- sumRange (3 + 1) 10 (3 + 3) 227 | sumRange 4 10 6 = -- sumRange (4 + 1) 10 (6 + 4) 228 | sumRange 5 10 10 = -- sumRange (5 + 1) 10 (10 + 5) 229 | sumRange 6 10 15 = -- sumRange (6 + 1) 10 (15 + 6) 230 | sumRange 7 10 21 = -- sumRange (7 + 1) 10 (21 + 7) 231 | sumRange 8 10 28 = -- sumRange (8 + 1) 10 (28 + 8) 232 | sumRange 9 10 36 = -- sumRange (9 + 1) 10 (36 + 9) 233 | sumRange 10 10 45 = -- sumRange (10 + 1) 10 (45 + 10) 234 | sumRange 11 10 55 = -- 11 > 10 => 55 235 | 55 236 | 237 | Você provavelmente está pensando que os loops **for** são mais fáceis de entender. Enquanto isto é discutível e mais como uma questão de **familiaridade**, loops não recursivos requerem Mutabilidade, o que é ruim. 238 | 239 | Eu não expliquei os benefícios da Imutabilidade aqui mas veja a seção **Global Mutate State** em [Por quê Programadores Precisam de Limites](https://medium.com/@cscalfani/why-programmers-need-limits-3d96e1a0a6db#.awvlo8d5l) para aprender mais. 240 | 241 | Um benefício óbvio é que se você tem acesso a um valor em seu programa, você somente tem acesso a leitura, o que significa que ninguém mais pode alterar este valor. Mesmo você. Então sem mutações acidentais. 242 | 243 | Além disso, se seu programa é multi-thread, então nenhuma outra thread pode puxar seu tapete. Aquele valor é constante e se outra thread quer mudá-lo, terá que criar um novo valor a partir do antigo. 244 | 245 | De volta aos anos 90, eu escrevi uma Game Engine para o [Creature Crunch](https://www.youtube.com/watch?v=uIOYSjBRORM) e a maior fonte de bugs foram em problemas multithreading. Desejava conhecer sobre imutabilidade naquela época. Mas lá atrás eu estava mais preocupado com a diferença entre as velocidades 2x ou 4x de um CD-ROM na performance do jogo. 246 | 247 | > Imutabilidade cria código simples e seguro. 248 | 249 | ### Meu cérebro!!! 250 | 251 | Por enquanto chega. 252 | 253 | Nas próximas partes deste artigo, eu vou falar sobre Higher-order Functions, Functional Composition, Currying e mais. 254 | 255 | A seguir: 256 | [Parte 2](parte-2.md) (em português) 257 | [Parte 2](https://medium.com/@cscalfani/so-you-want-to-be-a-functional-programmer-part-2-7005682cec4a) (em inglês) 258 | -------------------------------------------------------------------------------- /javascript/005-prototipos-javascript-em-uma-linguagem-simples.md: -------------------------------------------------------------------------------- 1 | # Protótipos Javascript em uma Linguagem Simples 2 | 3 | ![JS Prototype](../img/js-prototype.png) 4 | 5 | * **Artigo Original**: [JavaScript Prototype in Plain Language](http://javascriptissexy.com/javascript-prototype-in-plain-detailed-language/) 6 | * **Tradução**: [Eric Douglas](https://github.com/ericdouglas) 7 | 8 | **Protótipo** é um conceito fundamental que todo desenvolvedor JavaScript deve entender, e este post tem o objetivo de explicar o `prototype` JavaScript em uma linguagem simples e detalhada. Se você não entender o `prototype` JavaScript depois de ler este post, por favor coloque suas dúvidas nos comentários abaixo, eu vou pessoalmente responder todas as questões. 9 | 10 | Para entender o `prototype` em JavaScript você deve entender os objetos JavaScript. Se você não está familiar com os objetos, você deve ler meu post [Objetos JavaScript em detalhe](https://github.com/eoop/traduz-ai/blob/master/javascript/002-objetos-js-em-detalhe.md#objetos-javascript-em-detalhe). Igualmente, saber que uma *propriedade* é uma simples variável definida dentro de uma função. 11 | 12 | Existem dois conceitos inter-relacionados com `prototype` no JavaScript: 13 | 14 | **01** . Primeiro, existe uma **propriedade `prototype`** em toda função JavaScript (ela é vazia por padrão), e você anexa propriedades e métodos a essa propriedade `prototype` quando você quer implementar herança. Note que esta propriedade `prototype` não é enumerável: ela não está acessível em um loop for/in. Mas o Firefox, e a maioria das versões do Safari e Chrome, tem uma "pseudo" propriedade `__proto__` (de forma alternativa) que lhe permite acessar uma propriedade `prototype` de um objeto. Você provavelmente nunca vai usar esta pseudo propriedade `__proto__`, mas sabe que ela existe e é simplesmente uma forma de acessar uma propriedade `prototype` de um objeto em alguns navegadores. 15 | 16 | A propriedade `prototype` é usada primariamente para herança: você adiciona métodos e propriedades dentro de uma propriedade `prototype` de uma função para tornar estes métodos e propriedades disponíveis para instâncias desta função. 17 | 18 | Aqui temos um exemplo simples de herança com a propriedade `prototype` (mais sobre herança depois): 19 | 20 | ```javascript 21 | 22 | function PrintStuff (myDocuments) { 23 | this.documents = myDocuments; 24 | } 25 | 26 | // Nós adicionamos o método print() para a propriedade prototype de PrintStuff 27 | // então outras instâncias (objetos) podem herdá-la 28 | PrintStuff.prototype.print = function () { 29 | console.log(this.documents); 30 | }; 31 | 32 | // Cria um novo objeto com o construtor PrintStuff(), então permitindo 33 | // que este novo objeto de herde métodos e propriedades de PrintStuff 34 | var newObj = new PrintStuff("Eu sou um novo Objeto e eu posso imprimir."); 35 | 36 | // newObj herda todas as propriedades e métodos, incluindo o método print, 37 | // da função PrintStuff. Agora newObj pode chamar print diretamente, mesmo 38 | // nunca tendo criado um método print() nele. 39 | newObj.print(); // Eu sou um novo Objeto e eu posso imprimir. 40 | 41 | ``` 42 | 43 | **02** . O segundo conceito com `prototype` no JavaScript é o **atributo `prototype`**. Pense no atributo `prototype` como uma característica do objeto; esta característica nos informa o objeto "pai". Em simples palavras: um atributo `prototype` de um objeto aponta para o objeto "pai" - o objeto do qual foram herdadas as propriedades. O atributo `prototype` é normalmente referenciado como *objeto prototype*, e ele é configurado automaticamente quando você cria um novo objeto. Esclarecendo sobre isso: todo objeto herda propriedades de algum outro objeto, e este outro objeto é a propriedade prototype ou "pai". (Você pode pensar sobre o **atributo prototype** como uma linhagem ou o "pai"). No código acima, o `prototype` de `newObj` é `PrintStuff.prototype` 44 | 45 | Nota: Todos os objetos têm atributos como propriedades de objetos têm atributos. E os atributos do objeto são: `prototype`, `class` e `extensible`. É este atributo `prototype` que vamos discutir neste segundo exemplo. 46 | 47 | Note também que a "pseudo" propriedade `__proto__` contém um objeto prototype (o objeto pai que ela herda seus métodos e propriedades). 48 | 49 | ## Uma nota importante 50 | 51 | **Construtor** 52 | 53 | Antes de continuarmos, vamos rapidamente examinar o construtor. Um **construtor** é uma função usada para inicializar novos objetos, e você usa a palavra `new` para chamar o construtor. 54 | 55 | Por exemplo: 56 | 57 | ```javascript 58 | 59 | function Account () { 60 | 61 | } 62 | 63 | // Este é o uso do construtor Account para criar 64 | // um objeto userAccount 65 | var userAccount = new Account(); 66 | 67 | ``` 68 | 69 | Além disso, todos objetos que herdam de outro objeto também herdam uma propriedade `constructor`. E esta propriedade `constructor` é simplismente uma propriedade (como qualquer variável) que detém nossa indicação ao construtor do objeto. 70 | 71 | ```javascript 72 | 73 | // O construtor neste exemplo é Object() 74 | var myObj = new Object(); 75 | 76 | // e se depois você quiser encontrar o construtor de myObj 77 | console.log(myObj.constructor); // Object() 78 | 79 | // Outro exemplo: Account() é o construtor 80 | var userAccount = new Account(); 81 | 82 | // Encontra o construtor do objeto userAccount 83 | console.log(userAccount.constructor); // Account() 84 | 85 | ``` 86 | 87 | ## Atributo prototype de Objetos Criados com new Object() ou Objetos Literais 88 | 89 | Todos os objetos criados com objetos literais e com o construtor `Object` herdam de `Object.prototype`. Portanto, `Object.prototype` é o atributo `prototype` (ou o objeto prototype) de todos objetos criados com `new Object` ou com `{}`. `Object.prototype` não herda nenhum método ou propriedade de outro objeto. 90 | 91 | ```javascript 92 | 93 | // O objeto userAccount herda de Object e, como tal, 94 | // seu atributo prototype é Object.prototype 95 | var userAccount = new Object(); 96 | 97 | // Este exemplo demonstra o uso de um objeto literal para criar o objeto userAccount; 98 | // O objeto userAccount herda de Object; entretanto, seu atributo prototype é 99 | // o Object.prototype como o objeto userAccount acima. 100 | var userAccount = { name: "Mike" }; 101 | 102 | ``` 103 | 104 | **Atributo Prototype de Objetos Criados com uma Função Construtora** 105 | 106 | Objetos criados com a palavra-chave `new` e qualquer outro construtor além do construtor `Object()`, pegam seu prototype da função construtora. 107 | 108 | Por exemplo: 109 | 110 | ```javascript 111 | 112 | function Account () { 113 | 114 | } 115 | 116 | var userAccount = new Account() 117 | // userAccount inicializa com o construtor Account() 118 | // e portanto seu atributo prototype (ou objeto prototype) 119 | // é Account.prototype 120 | 121 | ``` 122 | 123 | Similarmente, qualquer array como `var myArray = new Array()`, pege seu prototype de `Array.prototype` e ele herda as propriedades de `Array.prototype`. 124 | 125 | Então, temos duas formas gerais que um atributo prototype de um objeto é configurado quando um objeto é criado: 126 | 127 | **1** . Se um objeto é criado com um objeto literal (`var newObj = {}`), ele herda as propriedades do `Object.prototype` e nós dizemos que seu objeto prototype (ou atributo prototype) é `Object.prototype`. 128 | 129 | **2** . Se um objeto é criado a partir de uma função construtora como `new Object()`, `new Fruit()` ou `new QualquerCoisa()`, ele herda do construtor `Object()`, `Fruit()`, `QualquerCoisa()`. Por exemplo, com uma função como `Fruit()`, cada vez que criarmos uma nova instância de Fruit (`var aFruit = new Fruit()`), o novo prototype da instância será atribuído ao prototype vindo do construtor Fruit, que é `Fruit.prototype`. Qualquer objeto que for criado com `new Array()` vai ter `Array.prototype` como seu prototype. Qualquer objeto criado com o construtor Object (`como var anObj = new Object()`) herda de `Object.prototype`. 130 | 131 | É importante conhecer que na ECMAScript 5, você pode criar objetos com um método `Object.create()` que permite que você configure novos `object.prototype` para os objetos. Nós vamos cobrir sobre ECMAScript em outro post. 132 | 133 | ## Por que Prototype é Importante e Quando ele é Usado? 134 | 135 | Estas são duas importantes maneiras em que o `prototype` é usado no JavaScript, como vimos acima: 136 | 137 | **1** . **Propriedade Prototype: Herança baseada em protótipos** 138 | 139 | O protótipo é importante no JavaScript porque o JavaScript não tem herança clássica baseada em Classes (como a maioria das linguagens orientadas a objeto têm), e portanto toda herança no JavaScript é possivelmente feita a partir da propriedade `prototype`. O JavaScript tem um mecanismo de herança baseado em protótipos. Herança é um paradigma de programação onde objetos (ou Classes em algumas linguagens) podem herdar propriedades e métodos de outros objetos (ou Classes). No JavaScript, você implementa herança com a propriedade `prototype`. Por exemplo, você pode criar uma função Fruit (um objeto, pois todas as funções no JavaScript são objetos) e adicionar propriedades e métodos na propriedade `prototype` de Fruit, e todas as instâncias da função Fruit vão herdar todas as propriedades e métodos de Fruit. 140 | 141 | Demonstração de herança no JavaScript: 142 | 143 | ```javascript 144 | 145 | function Plant() { 146 | this.country = "Mexico"; 147 | this.isOrganic = true; 148 | } 149 | 150 | // Adicionando o método shoeNameAndColor a propriedade prototype de Plant 151 | Plant.prototype.showNameAndColor = function () { 152 | console.log("I am a " + this.name + " and my color is " + this.color); 153 | } 154 | 155 | // Adicionando o método amIOrganic a propriedade prototype de Plant 156 | Plant.prototype.amIOrganic = function () { 157 | if (this.isOrganic) 158 | console.log("I am organic, baby!"); 159 | } 160 | 161 | function Fruit (fruitName, fruitColor) { 162 | this.name = fruitName; 163 | this.color = fruitColor; 164 | } 165 | 166 | // Configura o protótipo de Fruit para o construtor de Plant, 167 | // então herdando todos os métodos e propriedades de Plant.prototype 168 | Fruit.prototype = new Plant(); 169 | 170 | // Cria um novo objeto, aBanana, com o construtor Fruit 171 | var aBanana = new Fruit("Banana", "Yellow"); 172 | 173 | // Aqui, aBanana usa a propriedade name do objeto prototype aBanana, 174 | // que é Fruit.prototype: 175 | console.log(aBanana.name); // Banana 176 | 177 | // Usa o método showNameAndColor do objeto prototype Fruit, 178 | // que é Plant.prototype. O objeto aBanana herda todas as 179 | // propriedades e métodos de ambas funções Plant e Fruit. 180 | console.log(aBanana.showNameAndColor()); 181 | // I am a Banana and my color is yellow 182 | 183 | ``` 184 | 185 | Note que o método `showNameAndColor` foi herdado pelo objeto `aBanana` apesar de ter sido definido todo o caminho até a cadeia de protótipos do objeto Plant.prototype. 186 | 187 | De fato, qualquer objeto que usar o construtor `Fruit()` vai herdar todos os métodos e propriedades de `Fruit.prototype` e todos os métodos e propriedades do protótipo de Fruit, que é `Plant.prototype`. Esta é **a principal maneira que herança é implementada no JavaScript** e o papel essencial da cadeia de protótipos neste processo. 188 | 189 | Para uma cobertura mais aprofundada sobre Programação Orientada a Objetos no JavaScript, obtenha o livro de Nicholas Zakas [Principles of Object-Oriented Programming in JavaScript ](https://leanpub.com/oopinjavascript). 190 | 191 | **2** . **Atributo `prototype`: Acessando Propriedades nos Objetos** 192 | 193 | O protótipo também é importante para acessar propriedades e métodos de objetos. O **atributo `prototype`** (ou objeto prototype) de qualquer objeto é o objeto "pai" onde as propriedades herdadas foram originalmente definidas. Isto é vagamente análogo a forma que você pensa sobre o sobrenome de seu pai - ele é seu "protótipo pai". Se nós queremos encontrar de onde nosso sobrenome veio, nós devemos primeiro checar e ver se você o criou sozinho; se não, a busca será movida para o protótipo pai para ver se você herdou dele. Se não foi criado por ele, a busca continua pelo pai dele. 194 | 195 | Similarmente, se você quer acessar uma propriedade de um objeto, a busca pela propriedade começa diretamente no objeto. Se o *runtime* do JavaScript não conseguir encontrar a propriedade lá, ele então irá procurar pela propriedade no protótipo do objeto - o objeto que ele herdou suas propriedades. 196 | 197 | Se a propriedade não for encontrada no protótipo do objeto, a busca pela propriedade muda para o protótipo do protótipo do objeto (o pai do pai do objeto - o avô). E isto continua até que não tenha mais protótipos (sem mais bisavôs e sem mais linhagem a ser seguida). **Isso, em essência, é a cadeia de protótipos**: a cadeia de um protótipo de um objeto para seu protótipo do protótipo e por ai vai. O JavaScript usa esta cadeia de protótipos para verificar por propriedades e métodos de um objeto. Se a propriedade não existe em nenhum protótipo de objeto da sua cadeia prototípica, então a propriedade não existe e `undefined` é retornado. 198 | 199 | Esse mecanismo da cadeia de protótipos é essencialmente o mesmo conceito que discutimos acima com a herança baseada em protótipos, exceto que agora estamos focados especificamente em como o JavaScript acessa os métodos e propriedades dos objetos via o protótipo do objeto. 200 | 201 | Este exemplo demonstra a cadeia de protótipos de um objeto protótipo de um objeto: 202 | 203 | ```javascript 204 | 205 | var myFriends = {name: "Pete"}; 206 | 207 | // Para encontrar a propriedade name abaixo, a busca vai 208 | // iniciar diretamente no objeto myFriends e vai imediatamente 209 | // a propriedade name porque nós definimos a propriedade name 210 | // no objeto myFriends. Isto pode ser pensado como uma cadeia 211 | // de protótipos com um link 212 | console.log(myFriends.name); 213 | 214 | // Neste exemplo, a busca pelo método toString() 215 | // vai também começar no objeto myFriends, mas por 216 | // nós nunca termos criado um método toString() no 217 | // objeto myFriends, o compilador vai então buscar 218 | // por isso no protótipo de myFriends (o objeto que 219 | // ele herdou suas propriedades) 220 | 221 | // E uma vez que todos objetos criados com o objeto 222 | // literal herdam de Object.prototype, o método toString() 223 | // vai ser encontrado em Object.prototype - veja a importante 224 | // nota abaixo para todas propriedades herdadas de Object.prototype 225 | 226 | myFriends.toString(); 227 | 228 | ``` 229 | 230 | ### Uma Nota Importante 231 | 232 | > **Propriedades herdadas de Object.prototype por todos os objetos** 233 | > 234 | > Todos objetos no JavaScript herdam propriedades e métodos de `Object.prototype`. Estas propriedades e métodos herdados são `constructor`, `hasOwnProperty()`, `isPrototypeOf()`, `propertyIsEnumerable()`, `toLocaleString()`, `toString()`, e `valueOf()`. O ECMAScript 5 também adiciona 4 métodos de acesso a `Object.prototype`. 235 | 236 | Aqui um outro exemplo de cadeia prototípica: 237 | 238 | ```javascript 239 | 240 | function People () { 241 | this.superstar = "Michael Jackson"; 242 | } 243 | 244 | // Define a propriedade "athlete" no protótipo de People 245 | // então este "athlete" é acessível por todos os objetos 246 | // que usam o construtor People() 247 | People.prototype.athlete = "Tiger Woods"; 248 | 249 | var famousPerson = new People(); 250 | famousPerson.superstar = "Steve Jobs"; 251 | 252 | // A busca a superstar vai primeiramente verificar pela 253 | // propriedade superstar no objeto famousPerson, e uma vez 254 | // definido lá, esta é a propriedade que vai ser usada. 255 | // Por causa que nós sobrescrevemos a propriedade 256 | // superstar de famousPerson diretamente, a busca NÃO 257 | // vai prosseguir acima na cadeia de protótipos. 258 | console.log(famousPerson.superstar); // Steve Jobs 259 | 260 | // Note que no ECMAScript 5 você pode definir uma propriedade 261 | // para ser somente lida, e neste caso você não pode 262 | // sobrescrevê-la como fizemos anteriormente 263 | 264 | // Isto vai mostrar a propriedade do protótipo de famousPerson 265 | // (People.prototype) desde que a propriedade athlete não 266 | // tenha sido definida no objeto famousPerson 267 | console.log(famousPerson.athlete); // Tiger Woods 268 | 269 | // Neste exemplo, a busca prossegue na cadeia prototípica 270 | // e encontra o método toString do Object.prototype, o mesmo 271 | // que o objeto Fruit herdou - todos os objetos herdam de 272 | // Object.prototype como mencionamos acima. 273 | console.log(famousPerson.toString()); // [object Object] 274 | 275 | ``` 276 | 277 | Todos os construtores embutidos (`Array()`, `Number()`, `String()`, etc) foram criados a partir do construtor Object, e então `Object.prototype` é seus protótipos. 278 | 279 | **Informação Adicional** 280 | 281 | Para mais sobre Objetos JavaScript, leia o Capítulo 6 de JavaScript - O Guia Definitivo de David Flanagan. 282 | -------------------------------------------------------------------------------- /javascript/007-um-mergulho-no-javascript-puro.md: -------------------------------------------------------------------------------- 1 | # Um Mergulho no JavaScript Puro - Viljami S. 2 | 3 | * **Artigo Original**: [A Dive Into Plain JavaScript](http://blog.adtile.me/2014/01/16/a-dive-into-plain-javascript/) 4 | * **Tradução**: [Lucas F. Costa](https://github.com/lucasfcosta) 5 | 6 | Ainda que eu tenha trabalhado por mais de uma década construindo os mais diversos websites, fazem apenas 3 anos que comecei a aprender mais sobre como trabalhar com JavaScript puro ao invés de sempre usar jQuery como ponto de partida. O fato de que atualmente estou aprendendo uma dúzia de coisas novas todo dia fez com que o trabalho no projeto Adtile's JavaScript SDK parecesse mais com a construção de um projeto de código aberto do que um "trabalho de verdade" e eu tenho que dizer: gostei muito disso. 7 | 8 | Hoje eu vou compartilhar algumas das coisas básicas que aprendi durante os últimos anos, as quais espero que também te ajudem a mergulhar no mundo do JavaScript puro, tornando mais fácil a decisão de usar ou não jQuery no seu próximo projeto. 9 | 10 | ## Melhora Progressiva 11 | 12 | Enquanto libraries como [jQuery](http://jquery.com/) te ajudam a esquecer a maior parte das inconsistências entre navegadores, você vai ficar realmente familiarizado com eles assim que começar a usar JavaScript puro para tudo. Para evitar escrever um código cheio de "hacks" para o navegador e código que apenas resolve problemas de incompatibilidade entre navegadores, eu recomendo construir uma experiência melhorada progressivamente, usando uma detecção de funcionalidades para atingir somente os navegadores mais modernos. Isso não significa que navegadores como o IE7 não verão nada, significa apenas que eles obtêm uma experiência mais básica, sem melhoras no JavaScript. 13 | 14 | ## Aqui Está Como Vamos Fazer Isso 15 | 16 | Nós temos um fragmento JavaScript separado chamado "feature.js" que contém todos os testes de funcionalidades. A verdadeira lista de testes é muito mais longa, nós vamos voltar a nos preocupar com isso um pouco mais tarde. Para cortar alguns dos navegadores mais antigos, nós usamos esses dois testes: 17 | 18 | ```js 19 | var feature = { 20 | addEventListener : !!window.addEventListener, 21 | querySelectorAll : !!document.querySelectorAll, 22 | }; 23 | ``` 24 | 25 | Depois, na parte principal da aplicação, nós iremos detectar se essas funcionalidades são suportadas usando a simples declaração "`if`" abaixo. Caso elas não sejam suportadas o navegador não irá executar nada deste código: 26 | 27 | ```js 28 | if (feature.addEventListener && feature.querySelectorAll) { 29 | this.init(); 30 | } 31 | ``` 32 | 33 | Esses dois testes confirmam que nós temos uma maneira nativa de usar seletores CSS em JavaScript (`querySelectorAll`), uma maneira de adicionar e remover elementos facilmente (`addEventListener`) e também confirma que os padrões suportados pelo navegador são melhores do que os presentes no IE8. Leia mais sobre essa técnica chamada "Cortando a mostarda" no [Blog da BBC](http://responsivenews.co.uk/post/18948466399/cutting-the-mustard). 34 | 35 | ##Suporte ao navegador 36 | 37 | Aqui está uma lista "rústica" dos navegadores que suportam as funcionalides que estamos testando e consequentemente irão executar nosso JavaScript: 38 | 39 | * IE9+ 40 | * Firefox 3.5+ 41 | * Opera 9+ 42 | * Safari 4+ 43 | * Chrome 1+ 44 | * iPhone e iPad iOS1+ 45 | * Telefones e Tablets Android 2.1+ 46 | * Blackberry OS6+ 47 | * Windows 7.5+ 48 | * Firefox Mobile 49 | * Opera Mobile 50 | 51 | ##O Básico, a Maneira JavaScript Puro 52 | 53 | Vamos começar a ver como as funcionalidades mais básicas e frequentemente usadas funcionam em JavaScript puro comparadas ao jQuery. Para cada exemplo irei prover ambas as maneiras: com jQuery e usando JavaScript puro. 54 | 55 | ###Document Ready 56 | 57 | Com jQuery, muitos de vocês provavelmente estão acostumados a escrever o `document.ready` desta maneira: 58 | 59 | ```js 60 | $(document).ready(function() { 61 | // Code 62 | }); 63 | ``` 64 | 65 | Mas você sabia que você pode simplesmente colocar o seu JavaScript no final da página e ele vai fazer basicamente a mesma coisa? JavaScript também possui um *event listener* para o evento de quando o conteúdo DOM é carregado, sendo assim você também pode usar o código abaixo em vez do `document.ready` do jQuery: 66 | 67 | ```js 68 | document.addEventListener("DOMContentLoaded", function() { 69 | // Code 70 | }, false); 71 | ``` 72 | 73 | ##API de Seletores 74 | 75 | A API de seletores nativos do JavaScript é muito boa. Ela funciona com seletores CSS e é muito similar à que o jQuery provê. Se você está acostumado à escrever isso em jQuery: 76 | 77 | ```js 78 | var element = $("div"); 79 | ``` 80 | 81 | Você agora pode substituir isso por: 82 | 83 | ```js 84 | var element = document.querySelector("div"); 85 | ``` 86 | 87 | Ou, para selecionar todos os `div`'s dentro de um determinado container: 88 | 89 | ```js 90 | var elements = document.querySelectorAll(".container div"); 91 | ``` 92 | 93 | Você também pode buscar por um elemento específico para encontrar seu respectivo filho: 94 | 95 | ```js 96 | var navigation = document.querySelector("nav"); 97 | var links = navigation.querySelectorAll("a"); 98 | ``` 99 | 100 | Muito objetivo, fácil de entender e não requer, necessariamente, muito mais escrita, não é mesmo? Para ir um pouco além nós podemos até construir uma pequena *library* em JavaScript para que possamos fazer buscas no DOM de maneira mais simplificada. Aqui está uma ideia que Andrew Lunny teve: 101 | 102 | ```js 103 | 104 | // Isso nos dá uma simples função representada pelo símbolo de dólar e uma ligação com um evento na linha seguinte 105 | var $ = document.querySelectorAll.bind(document); 106 | Element.prototype.on = Element.prototype.addEventListener; 107 | 108 | // Assim é como você usa isso 109 | $(".element")[0].on("touchstart", handleTouch, false); 110 | ``` 111 | 112 | ##Navegando pelo DOM 113 | 114 | Navegar pelo DOM com JavaScript puro é um pouco mais difícil do que com jQuery. Mas não é difícil demais. Aqui estão alguns exemplos simples: 115 | 116 | ```js 117 | // Obtendo o nó pai 118 | var parent = document.querySelector("div").parentNode; 119 | 120 | // Obtendo o nó de texto 121 | var next = document.querySelector("div").nextSibling; 122 | 123 | // Obtendo o nó anterior 124 | var next = document.querySelector("div").previousSibling; 125 | 126 | // Obtendo o primeiro elemento filho 127 | var child = document.querySelector("div").children[0]; 128 | 129 | // Obtendo o último filho 130 | var last = document.querySelector("div").lastElementChild; 131 | ``` 132 | 133 | ##Adicionando e Removendo Classes 134 | 135 | Com jQuery, adicionar, remover e checar se um elemento possui certas classes é muito simples. É um pouco mais complexo se usarmos JavaScript puro. Dar a um elemento uma classe chamada "foo" e substituir todas as classes atuais fica algo como: 136 | 137 | ```js 138 | // Selecione um elemento 139 | var element = document.querySelector(".alguma-classe"); 140 | 141 | // Dê a classe "foo" ao elemento 142 | element.className = "foo"; 143 | ``` 144 | 145 | Adicionando uma classe sem substituir as classes atuais: 146 | 147 | ```js 148 | element.className += " foo"; 149 | ``` 150 | 151 | Removendo a classe "no-js" de um elemento html e substituindo-a por "js": 152 | 153 | ```js 154 | 155 | 156 | 159 | …… 160 | ``` 161 | 162 | Foi bem objetivo, não é mesmo? Vamos para o próximo passo, que é remover apenas certas classes. Isso é um pouco mais complexo. Eu estive usando essa pequena "função ajudante" em um fragmento separado chamado *util.js*. Ela leva 2 parâmetros: elemento e a classe que você quer remover: 163 | 164 | ```js 165 | // removeClass, leva dois parâmetros: elemento(el) e nome da classe (cls) 166 | function removeClass(el, cls) { 167 | var reg = new RegExp("(\\s|^)" + cls + "(\\s|$)"); 168 | el.className = el.className.replace(reg, " ").replace(/(^\s*)|(\s*$)/g,""); 169 | } 170 | ``` 171 | 172 | Depois, no fragmento principal da aplicação eu usei-a desta maneira: 173 | 174 | ```js 175 | removeClass(element, "foo"); 176 | ``` 177 | 178 | Se você também quiser checar um elemento quanto a sua pertinência a alguma classe, da mesma maneira que o `hasClass` do jQuery funciona, você pode adicionar isso no seu fragmento `utils`: 179 | 180 | ```js 181 | // hasClass, aceita dois parâmentros: elemento(el) e nome da classe(cls) 182 | function hasClass(el, cls) { 183 | return el.className && new RegExp("(\\s|^)" + cls + "(\\s|$)").test(el.className); 184 | } 185 | ``` 186 | 187 | ...e usar dessa maneira: 188 | 189 | ```js 190 | // Checa se um elemento possui a classe "foo" 191 | if (hasClass(element, "foo")) { 192 | 193 | // E mostra uma mensagem caso ele possua 194 | alert("O elemento tem essa classe!"); 195 | } 196 | ``` 197 | 198 | ##Introduzindo a API classList do HTML5 199 | 200 | Se você precisa apenas dar suporte aos navegadores modernos como IE10+, Chrome, Firefox, Opera e Safari, você pode começar usando a funcionalidade `classList` do HTML5, a qual faz com que adicionar ou retirar classes se torne muito mais fácil. 201 | 202 | Isso é algo que eu acabei fazendo com a nossa última documentação de desenvolvedores. Como a funcionalidade que eu estava desenvolvendo era mais relacionada à uma melhora na interface de usuário e não era algo realmente essencial e que quebraria a experiência se não estivesse presente, decidi implementar. 203 | 204 | Você pode detectar se o navegador suporta essa funcionalidade usando essa simples declaração "`if`": 205 | 206 | ```js 207 | if ("classList" in document.documentElement) { 208 | // classList é suportado dentro desse bloco, agora faça algo com ele 209 | } 210 | ``` 211 | 212 | Adicionando, removendo e alternando classes com classList: 213 | 214 | ```js 215 | // Adicionando uma classe 216 | element.classList.add("bar"); 217 | 218 | // Removendo uma classe 219 | element.classList.remove("foo"); 220 | 221 | // Checando se contém uma classe 222 | element.classList.contains("foo"); 223 | 224 | // Alternando uma classe 225 | element.classList.toggle("active"); 226 | ``` 227 | 228 | Um outro benefício de usar `classList` é que sua performance vai ser muito melhor do que usar a propriedade `className` pura. Se você tivesse um elemento como esse: 229 | 230 | ```js 231 |

    232 | ``` 233 | 234 | O qual você quisesse manipular: 235 | 236 | ```js 237 | var element = document.querySelector("#test"); 238 | addClass(element, "two"); 239 | removeClass(element, "four"); 240 | ``` 241 | 242 | Para cada um desses métodos, a propriedade `className` seria lida do elemento e depois reescrita, fazendo um com que o navegador tenha que redesenhar a página. Ainda assim, esse não é o caso se quisermos usar os métodos relevantes da funcionalidade `classList`: 243 | 244 | ```js 245 | var element = document.querySelector("#test"); 246 | element.classList.add("two"); 247 | element.classList.remove("four"); 248 | ``` 249 | 250 | Com `classList` a propriedade base `className` é apenas alterada quando necessário. Dado que nós estamos adicionando uma classe que já é presente e removendo uma classe que não é, a propriedade `className` permanece intocada, isso significa que nós acabamos de evitar dois rdeesenhos! 251 | 252 | ##Detectores de Evento (*Event Listeners*) 253 | 254 | Adicionar e remover detectores de evento de elementos em JavaScript puro é quase tão simples quanto em jQuery. As coisas ficam um pouco mais complexas quando você tem que adicionar múltiplos detectores de evento, mas eu vou explicar isso logo logo! O exemplo mais simples, o qual irá apenas fazer com que uma mensagem de alerta apareça quando um elemento é clicado, é o seguinte: 255 | 256 | ```js 257 | element.addEventListener("click", function() { 258 | alert("Você clicou"); 259 | }, false); 260 | ``` 261 | 262 | Para conseguir essa mesma funcionalidade em todos os elementos de uma dada página nós vamos ter que fazer uma repetição através de todos os elementos, um por um, e dar a todos eles detectores de eventos: 263 | 264 | ```js 265 | // Seleciona todos os links 266 | var links = document.querySelectorAll("a"); 267 | 268 | // Para cada elemento link 269 | [].forEach.call(links, function(el) { 270 | 271 | // Adiciona um detector de evento 272 | el.addEventListener("click", function(event) { 273 | event.preventDefault(); 274 | alert("You clicked"); 275 | }, false); 276 | 277 | }); 278 | ``` 279 | 280 | Uma das funcionalidades relacionadas a detectores de eventos mais legais do JavaScript é o fato de que "`addEventListener`" pode levar um objeto como segundo argumento, o qual vai automaticamente procurar por um método chamado "`handleEvent`" e chamá-lo. [Ryan Seddon](https://twitter.com/ryanseddon) já falou sobre essa técnica [neste artigo](http://www.thecssninja.com/javascript/handleevent), então eu vou apenas dar um exemplo rápido e depois você pode ler mais sobre isso no blog dele: 281 | 282 | ```js 283 | var object = { 284 | init: function() { 285 | button.addEventListener("click", this, false); 286 | button.addEventListener("touchstart", this, false); 287 | }, 288 | handleEvent: function(e) { 289 | switch(e.type) { 290 | case "click": 291 | this.action(); 292 | break; 293 | case "touchstart": 294 | this.action(); 295 | break; 296 | } 297 | }, 298 | action: function() { 299 | alert("Clicado ou tocado!"); 300 | } 301 | }; 302 | 303 | // Init 304 | object.init(); 305 | ``` 306 | 307 | ##Manipulando o DOM 308 | 309 | Manipular o DOM com JavaScript puro pode soar como uma ideia horrível à primeira vista, mas não é muito mais complexo do que usar jQuery. Abaixo nós temos um exemplo que seleciona um elemento do DOM, cloná-o, manipula o estilo do clone com JavaScript e depois substitui o elemento original pelo elemento que foi manipulado. 310 | 311 | ```js 312 | // Select an element 313 | var element = document.querySelector(".class"); 314 | 315 | // Clone it 316 | var clone = element.cloneNode(true); 317 | 318 | // Do some manipulation off the DOM 319 | clone.style.background = "#000"; 320 | 321 | // Replaces the original element with the new cloned one 322 | element.parentNode.replaceChild(clone, element); 323 | ``` 324 | 325 | Se você não quer substituir nada no DOM, mas em vez disso apenas anexar o novo `div` dentro da *tag* ``, você pode fazer algo como: 326 | 327 | ```js 328 | document.body.appendChild(clone); 329 | ``` 330 | 331 | Se você quiser ler ainda mais sobre outros métodos relacionados ao DOM, eu sugiro que você se encaminhe para as [Tabelas Essenciais do DOM](http://quirksmode.org/dom/core/) do Peter-Paul Koch. 332 | 333 | ##Mergulhando Ainda Mais Fundo 334 | 335 | Eu irei compartilhar mais duas técnicas avançadas aqui, as quais eu descobri recentemente. Ambas são funcionalidades que precisamos enquanto estávamos construindo o [Addtile](http://www.adtile.me/), então talvez você possa considerá-las úteis também. 336 | 337 | ##Determinando a Largura Máxima de Imagens Responsivas em JS 338 | 339 | Esse é, pessoalmente, um dos meus favoritos e é muito útil se você alguma vez já precisou manipular imagens fluídas com JavaScript. Como os navegadores costumam retornar tamanhos redimensionados de imagens por padrão, nós tivemos que desenvolver alguma outra solução. Por sorte, navegadores modernos agora possuem uma maneira de fazer isso: 340 | 341 | ```js 342 | var maxWidth = img.naturalWidth; 343 | ``` 344 | 345 | Isso irá nos dar o valor do atributo `max-width: 100%` da imagem em pixels e é suportado no IE9, Chrome, Firefox, Safari e Opera. Nós também podemos levar isso mais além e adicionar suporte para navegadores antigos carregando a imagem em um objeto na memória: 346 | 347 | ```js 348 | // Pega o atributo max-width:100%; da imagem em pixels 349 | function getMaxWidth(img) { 350 | var maxWidth; 351 | 352 | // Checa se naturalWidth é suportado 353 | if (img.naturalWidth !== undefined) { 354 | maxWidth = img.naturalWidth; 355 | 356 | // Não suportado, use a solução de carregar na memória como plano B 357 | } else { 358 | var image = new Image(); 359 | image.src = img.src; 360 | maxWidth = image.width; 361 | } 362 | 363 | // Retorne o max-width 364 | return maxWidth; 365 | } 366 | ``` 367 | 368 | Você deve notar que as imagens devem ser totalmente carregadas antes de checar a largura. Isso é o que nós estamos usando para ter certeza que as imagens possuem dimensões: 369 | 370 | ```js 371 | function hasDimensions(img) { 372 | return !!((img.complete && typeof img.naturalWidth !== "undefined") || img.width); 373 | } 374 | ``` 375 | 376 | ##Determinando se um Elemento Está no Campo de Visão (Viewport) 377 | 378 | Você pode obter a posição de qualquer elemento na página usando o método [getBoundingClientRect](https://developer.mozilla.org/en-US/docs/Web/API/Element.getBoundingClientRect). Abaixo está uma simples função mostrando o quão simples e poderoso isso pode ser. Essa função leva um parâmetro, que é o elemento o qual você quer checar. Ela irá retornar `true` quando o elemento estiver visível: 379 | 380 | ```js 381 | // Determina se um elemento está no campo de visão 382 | function isInViewport(element) { 383 | var rect = element.getBoundingClientRect(); 384 | var html = document.documentElement; 385 | return ( 386 | rect.top >= 0 && 387 | rect.left >= 0 && 388 | rect.bottom <= (window.innerHeight || html.clientHeight) && 389 | rect.right <= (window.innerWidth || html.clientWidth) 390 | ); 391 | } 392 | ``` 393 | 394 | A função acima pode ser usada adicionando um detector de evento "`scroll`" (rolagem) à janela e depois chamando `isInViewport()` 395 | 396 | ##Conclusão 397 | 398 | Se você deve ou não usar jQuery no seu próximo projeto depende muito do que você estiver construindo. Se é algo que requer grandes quantidades de código *front-end*, você provavelmente deve usá-lo. No entanto, se você estiver construindo um *plugin* ou uma *library* JavaScript, você pode querer considerar a possibilidade de usar apenas JavaScript puro. Usar JavaScript puro significa menos requisições e menos dados para carregar. Também significa que você não está forçando outros desenvolvedores a adicionarem jQuery ao projeto deles só por causa de sua dependência. 399 | --------------------------------------------------------------------------------