{"id":3713,"date":"2014-11-10T10:21:06","date_gmt":"2014-11-10T12:21:06","guid":{"rendered":"http:\/\/blog.turbosite.com.br\/?p=3713"},"modified":"2014-11-10T10:21:06","modified_gmt":"2014-11-10T12:21:06","slug":"entenda-o-que-sao-closures-em-javascript","status":"publish","type":"post","link":"https:\/\/www.turbosite.com.br\/blog\/entenda-o-que-sao-closures-em-javascript\/","title":{"rendered":"Entenda o que s\u00e3o Closures em JavaScript"},"content":{"rendered":"<p>Encontramos uma publica\u00e7\u00e3o do blog\u00a0<a title=\"Javascript Brasil\" href=\"http:\/\/javascriptbrasil.com\/2013\/10\/12\/entenda-closures-no-javascript-com-facilidade\/\" rel=\"home\">Javascript Brasil<\/a>\u00a0que explica, com facilidade, o que s\u00e3o <strong>Closures<\/strong> em <strong>JavaScript<\/strong>. Closures permitem uma programa\u00e7\u00e3o\u00a0criativa e concisamente. Eles s\u00e3o usados frequentemente no JavaScript, sendo\u00a0f\u00e1ceis de se entender e atraentes para serem usados em seus projetos. \u00c9\u00a0bastante comum encontrar closures em c\u00f3digos <em>jQuery<\/em> e <em>Node.js<\/em>. Abaixo voc\u00ea pode conferir um cl\u00e1ssico exemplo de closure em jQuery.<\/p>\n<pre class=\"lang:js decode:true\">$(function () {\n\u00a0\u00a0\u00a0\u00a0var selections = [];\n\u00a0\u00a0\u00a0\u00a0$(\".niners\").click(function () {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0selections.push(this.prop (\"name\"));\n\u00a0\u00a0\u00a0\u00a0});\n});<\/pre>\n<p>A equipe da <a href=\"https:\/\/www.turbosite.com.br\/\">Turbosite<\/a> repassamos esse conhecimento com a\u00a0postagem abaixo.<\/p>\n<p>&nbsp;<\/p>\n<h2><strong>O que \u00e9 um closure?<\/strong><\/h2>\n<p>Um closure \u00e9 uma fun\u00e7\u00e3o interior que tem acesso a vari\u00e1veis de uma fun\u00e7\u00e3o exterior \u2013 cadeia de escopo. O closure tem tr\u00eas cadeias de escopo: o seu pr\u00f3prio escopo; escopo externo, tendo acesso as vari\u00e1veis da fun\u00e7\u00e3o exterior; e tem acesso as vari\u00e1veis globais.<\/p>\n<p>A fun\u00e7\u00e3o interior tem acesso n\u00e3o somente as vari\u00e1veis da fun\u00e7\u00e3o exterior, mas tamb\u00e9m aos par\u00e2metros dela. Note que a fun\u00e7\u00e3o interior n\u00e3o pode chamar o objeto(<i>arguments)<\/i>\u00a0da fun\u00e7\u00e3o exterior, entretanto, pode chamar par\u00e2metros da fun\u00e7\u00e3o externa diretamente.<\/p>\n<p>Voc\u00ea cria um closure adicionando uma fun\u00e7\u00e3o dentro de outra fun\u00e7\u00e3o.<\/p>\n<div id=\"crayon-54609aabf262f135225674\" class=\"crayon-syntax crayon-theme-classic crayon-font-monaco crayon-os-pc print-yes notranslate\" data-settings=\" minimize scroll-mouseover\">\n<div class=\"crayon-main\">\n<pre class=\"lang:js decode:true\">function showName (firstName, lastName) {\n\u00a0\u00a0\u00a0\u00a0var nameIntro = \"Your name is \";\n\u00a0\n\u00a0\u00a0\u00a0\u00a0\/\/esta fun\u00e7\u00e3o interior tem acesso as vari\u00e1veis da fun\u00e7\u00e3o exterior, incluindo os par\u00e2metros\n\u00a0\u00a0\u00a0\u00a0function makeFullName () {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return nameIntro + firstName + \" \" + lastName;\n\u00a0\u00a0\u00a0\u00a0}\n\u00a0\n\u00a0\u00a0\u00a0\u00a0return makeFullName ();\n}\n\u00a0\nshowName (\"Michael\", \"Jackson\"); \/\/Your name is Michael Jackson<\/pre>\n<\/div>\n<\/div>\n<div id=\"crayon-54609aabf2640726497822\" class=\"crayon-syntax crayon-theme-classic crayon-font-monaco crayon-os-pc print-yes notranslate\" data-settings=\" minimize scroll-mouseover\"><\/div>\n<h2><strong>Regra dos Closures e Efeitos Colaterais<\/strong><\/h2>\n<h3><strong>1. Closures tem acesso a vari\u00e1vel das fun\u00e7\u00f5es exteriores mesmo ap\u00f3s o retorno da fun\u00e7\u00e3o exterior<\/strong><\/h3>\n<p>Uma da mais importante e delicada caracter\u00edstica dos closures \u00e9 que a fun\u00e7\u00e3o interior continua tendo acesso as vari\u00e1veis da fun\u00e7\u00e3o exterior mesmo ap\u00f3s ela ter retornado. \u00a0Quando fun\u00e7\u00f5es no JavaScript executam, elas usam a mesma cadeia de escopo que estava em vigor quando foram criadas. Isso significa que mesmo depois da fun\u00e7\u00e3o exterior retornar, a fun\u00e7\u00e3o interior continua tendo acesso as vari\u00e1veis da fun\u00e7\u00e3o exterior. Portanto, voc\u00ea pode chamar a fun\u00e7\u00e3o interior depois em seu programa. Este exemplo demonstra isso:<\/p>\n<div id=\"crayon-54609aabf2647041099827\" class=\"crayon-syntax crayon-theme-classic crayon-font-monaco crayon-os-pc print-yes notranslate\" data-settings=\" minimize scroll-mouseover\">\n<div class=\"crayon-main\">\n<pre class=\"lang:js decode:true \">function celebrityName (firstName) {\n\u00a0\u00a0\u00a0\u00a0var nameIntro = \"This celebrity is \";\n\u00a0\n\u00a0\u00a0\u00a0\u00a0\/\/essa fun\u00e7\u00e3o interior tem acesso as vari\u00e1veis da fun\u00e7\u00e3o exterior, incluindo os par\u00e2metros\n\u00a0\u00a0\u00a0\u00a0function lastName (theLastName) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return nameIntro + firstName + \" \" + theLastName;\n\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0return lastName;\n}\n\u00a0\nvar mjName = celebrityName (\"Michael\");\n\/\/Nesta conjuntura, a fun\u00e7\u00e3o exterior celebrityName foi retornada\n\u00a0\n\/\/O closure (lastName) \u00e9 chamado aqui depois da fun\u00e7\u00e3o exterior ter retornado acima\n\/\/Sim, o closure continua tendo acesso as vari\u00e1veis da fun\u00e7\u00e3o exterior e par\u00e2metros\nmjName (\"Jackson\"); \/\/This celebrity is Michael Jackson<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<\/div>\n<h3><strong>2. Closures armazenam refer\u00eancias para as vari\u00e1veis da fun\u00e7\u00e3o exterior<\/strong><\/h3>\n<p>Eles n\u00e3o armazenam o valor real. Closures ficam mais interessantes quando o valor da vari\u00e1vel da fun\u00e7\u00e3o exterior muda antes que o closure seja chamado, e esta poderosa caracter\u00edstica pode ser aproveitada de formas criativas, como este exemplo de vari\u00e1vel privada primeiramente demonstrada por Douglas Crockford:<\/p>\n<div id=\"crayon-54609aabf264d409673630\" class=\"crayon-syntax crayon-theme-classic crayon-font-monaco crayon-os-pc print-yes notranslate\" data-settings=\" minimize scroll-mouseover\">\n<div class=\"crayon-plain-wrap\">\n<pre class=\"lang:js decode:true \">function celebrityID () {\n\u00a0\u00a0\u00a0\u00a0var celebrityID = 999;\n\u00a0\u00a0\u00a0\u00a0\/\/N\u00f3s retornamos um objeto com algumas fun\u00e7\u00f5es interiores\n\u00a0\u00a0\u00a0\u00a0\/\/Todas as fun\u00e7\u00f5es interiores t\u00eam acesso as vari\u00e1veis'da fun\u00e7\u00e3o exterior\n\u00a0\u00a0\u00a0\u00a0return {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0getID: function () {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/Esta fun\u00e7\u00e3o interior vai retornar a vari\u00e1vel celebrityID ATUALIZADA\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return celebrityID;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0},\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0setID: function (theNewId) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/Esta fun\u00e7\u00e3o interior vai mudar a vari\u00e1vel da fun\u00e7\u00e3o exterior a qualquer hora\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0celebrityID = theNewId;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0}\n}\n\u00a0\nvar mjID = celebrityID (); \/\/Nesta atual conjuntura, a fun\u00e7\u00e3o exterior celebrityID j\u00e1 retornou\nmjID.getID(); \/\/999\nmjID.setID(567); \/\/Muda a vari\u00e1vel da fun\u00e7\u00e3o exterior\nmjID.getID(); \/\/567 - retorna o valor atualizado da vari\u00e1vel celebrityID<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<\/div>\n<p>&nbsp;<\/p>\n<h3><strong>3. Closures que deram errado<\/strong><\/h3>\n<p>Por causa dos closures terem acesso ao valor atualizado das vari\u00e1veis das fun\u00e7\u00f5es exteriores, eles podem tamb\u00e9m conduzir a erros quando a vari\u00e1vel da fun\u00e7\u00e3o exterior muda com um loop for. Assim:<\/p>\n<pre class=\"lang:js decode:true \">\/\/Este exemplo \u00e9 explicado em detalhe abaixo (logo ap\u00f3s este bloco de c\u00f3digo)\nfunction celebrityIDCreator (theCelebrities) {\n\u00a0\u00a0\u00a0\u00a0var i;\n\u00a0\u00a0\u00a0\u00a0var uniqueID = 100;\n\u00a0\u00a0\u00a0\u00a0for (i = 0; i &amp;lt; theCelebrities.length; i += 1) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0theCelebrities[i][\"id\"] = function () {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return uniqueID + i;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0}\n\u00a0\n\u00a0\u00a0\u00a0\u00a0return theCelebrities;\n}\n\u00a0\nvar actionCelebs = [{name:\"Stallone\", id:0}, {name:\"Cruise\", id:0}, {name:\"Willis\", id:0}];\n\u00a0\nvar createIdForActionCelebs = celebrityIDCreator(actionCelebs);\n\u00a0\nvar stalloneID = createIdForActionCelebs[0];\n\u00a0\nconsole.log(stalloneID.id()); \/\/103<\/pre>\n<p>No exemplo anterior, quando a fun\u00e7\u00e3o an\u00f4nima \u00e9 chamada, o valor de i \u00e9 3 (a contagem do array e ent\u00e3o seus incrementos). O n\u00famero 3 foi adicionado ao uniqueID para criar 103 para TODOS os celebrityID. Ent\u00e3o cada posi\u00e7\u00e3o no array retornado obteve o id = 103, ao inv\u00e9s do valor pretendido 100, 101, 102.<\/p>\n<p>A raz\u00e3o para isso acontecer foi porque, assim como n\u00f3s discutimos no exemplo anterior, o closure (fun\u00e7\u00e3o an\u00f4nima neste exemplo) teve acesso a vari\u00e1vel da fun\u00e7\u00e3o exemplo por refer\u00eancia, n\u00e3o por valor. Ent\u00e3o, igual ao exemplo anteriormente mostrado onde n\u00f3s acessamos o valor atualizado da vari\u00e1vel com o closure, neste exemplo, similarmente acessamos a vari\u00e1vel i quando ela foi alterada, depois que a fun\u00e7\u00e3o exterior rodou o loop for inteiro e retornou o \u00faltimo valor, que foi 103.<\/p>\n<p>Para consertar este efeito colateral (bug) nos closures, voc\u00ea pode usar uma\u00a0<strong>Express\u00e3o de Fun\u00e7\u00e3o Imediatamente Invocada<\/strong> (IIFE \u2013 Immediately Invoked Function Expression), como no exemplo seguinte:<\/p>\n<div id=\"crayon-54609aabf265a506956951\" class=\"crayon-syntax crayon-theme-classic crayon-font-monaco crayon-os-pc print-yes notranslate\" data-settings=\" minimize scroll-mouseover\">\n<div class=\"crayon-toolbar\" data-settings=\" mouseover overlay hide delay\">\n<pre class=\"lang:js decode:true \">function celebrityIDCreator (theCelebrities) {\n\u00a0\u00a0\u00a0\u00a0var i;\n\u00a0\u00a0\u00a0\u00a0var uniqueID = 100;\n\u00a0\u00a0\u00a0\u00a0for (i = 0; i &amp;lt; theCelebrities.length; i += 1) {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0theCelebrities[i][\"id\"] = function (j) { \/\/a vari\u00e1vel param\u00e9trica j \u00e9 o i passado na invoca\u00e7\u00e3o da IIFE\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return function () {\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0return uniqueID + j;\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\/\/cada itera\u00e7\u00e3o do loop for passa no valor atual de i dentro desta IIFE e salva o valor correto no array\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0} () \/\/Adicionando () no fim da fun\u00e7\u00e3o, n\u00f3s estamos executando-a imediatamente e retornando somente o valor de uniqueID + j, ao inv\u00e9s de retornar uma fun\u00e7\u00e3o\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0} (i); \/\/invocando imediatamente a fun\u00e7\u00e3o passando a vari\u00e1vel i como um par\u00e2metro\n\u00a0\u00a0\u00a0\u00a0}\n\u00a0\u00a0\u00a0\u00a0return theCelebrities;\n}\n\u00a0\nvar actionCelebs = [{name: \"Stallone\", id:0}, {name: \"Cruise\", id:0}, {name: \"Willis\", id:0}];\n\u00a0\nvar createIdForActionCelebs = celebrityIDCreator (actionCelebs);\n\u00a0\nvar stalloneID = createIdForActionCelebs [0];\nconsole.log(stalloneID.id); \/\/100\n\u00a0\nvar cruiseID = createIdForActionCelebs [1];\nconsole.log(cruiseID.id); \/\/101<\/pre>\n<p>&nbsp;<\/p>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Entenda com facilidade o que s\u00e3o Closures em JavaScript. Muito usado em jQuery e Node.js, Closures permitem uma programa\u00e7\u00e3o criativa e concisamente.<\/p>\n","protected":false},"author":1,"featured_media":3717,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6,15],"tags":[108,361],"class_list":["post-3713","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dicas","category-javascript","tag-closure","tag-javascript-2"],"_links":{"self":[{"href":"https:\/\/www.turbosite.com.br\/blog\/wp-json\/wp\/v2\/posts\/3713","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.turbosite.com.br\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.turbosite.com.br\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.turbosite.com.br\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.turbosite.com.br\/blog\/wp-json\/wp\/v2\/comments?post=3713"}],"version-history":[{"count":0,"href":"https:\/\/www.turbosite.com.br\/blog\/wp-json\/wp\/v2\/posts\/3713\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.turbosite.com.br\/blog\/wp-json\/wp\/v2\/media\/3717"}],"wp:attachment":[{"href":"https:\/\/www.turbosite.com.br\/blog\/wp-json\/wp\/v2\/media?parent=3713"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.turbosite.com.br\/blog\/wp-json\/wp\/v2\/categories?post=3713"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.turbosite.com.br\/blog\/wp-json\/wp\/v2\/tags?post=3713"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}