diff options
Diffstat (limited to 'files/pt-br/web/javascript/reference/functions/arrow_functions')
-rw-r--r-- | files/pt-br/web/javascript/reference/functions/arrow_functions/index.html | 384 |
1 files changed, 384 insertions, 0 deletions
diff --git a/files/pt-br/web/javascript/reference/functions/arrow_functions/index.html b/files/pt-br/web/javascript/reference/functions/arrow_functions/index.html new file mode 100644 index 0000000000..1694545a71 --- /dev/null +++ b/files/pt-br/web/javascript/reference/functions/arrow_functions/index.html @@ -0,0 +1,384 @@ +--- +title: Arrow functions +slug: Web/JavaScript/Reference/Functions/Arrow_functions +tags: + - ECMAScript 2015 + - Funções + - Intermediário + - JavaScript + - Referencia +translation_of: Web/JavaScript/Reference/Functions/Arrow_functions +--- +<div>{{jsSidebar("Functions")}}</div> + +<p>Uma <strong>expressão <em>arrow function</em></strong> possui uma sintaxe mais curta quando comparada a uma expressão de função (<em><a href="/pt-BR/docs/Web/JavaScript/Reference/Operators/function">function expression</a></em>) e não tem seu próprio <em><a href="/pt-BR/docs/Web/JavaScript/Reference/Operators/this">this</a></em>, <em><a href="/pt-BR/docs/Web/JavaScript/Reference/Functions/arguments">arguments</a></em>, <em><a href="/pt-BR/docs/Web/JavaScript/Reference/Operators/super">super</a></em> ou <em><a href="/pt-BR/docs/Web/JavaScript/Reference/Operators/new.target">new.target</a></em>. Estas expressões de funções são melhor aplicadas para funções que não sejam métodos, e elas não podem ser usadas como construtoras (<em>constructors</em>).</p> + +<p>{{EmbedInteractiveExample("pages/js/functions-arrow.html")}}</p> + +<h2 id="Syntax" name="Syntax">Sintaxe</h2> + +<h3 id="Sintaxe_básica">Sintaxe básica</h3> + +<pre>(param1, param2, …, paramN) => { statements } +(param1, param2, …, paramN) => expression +// equivalente a: => { return expression; } + +// Parênteses são opcionais quando só há um nome de parâmetro: +(singleParam) => { statements } +singleParam => { statements } + +// A lista de parâmetros para uma função sem parâmetros deve ser escrita com um par de parênteses. +() => { statements }</pre> + +<h3 id="Sintaxe_avançada">Sintaxe avançada</h3> + +<pre>// Envolva o corpo da função em parênteses para retornar uma expressão literal de objeto: +params => ({foo: bar}) + +// Parâmetros rest (<em><a href="/pt-BR/docs/Web/JavaScript/Reference/Functions/rest_parameters">rest parameters</a>)</em> e parâmetros padrões (<em><a href="/pt-BR/docs/Web/JavaScript/Reference/Functions/Default_parameters">default parameters</a></em>) são suportados +(param1, param2, ...rest) => { statements } +(param1 = defaultValue1, param2, …, paramN = defaultValueN) => { statements } + +// Desestruturação (<em><a href="/pt-BR/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment">destructuring</a></em>) dentro da lista de parâmetros também é suportado +var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c; +f(); // 6</pre> + +<h2 id="Descrição">Descrição</h2> + +<p>Veja também <a href="https://hacks.mozilla.org/2015/06/es6-in-depth-arrow-functions/">"ES6 In Depth: Arrow functions" on hacks.mozilla.org</a>.</p> + +<p>Dois fatores influenciaram a introdução das <em>arrow functions</em>: funções mais curtas e a inexistência da palavra chave <code>this</code>.</p> + +<h3 id="Funções_mais_curtas">Funções mais curtas</h3> + +<pre><code>var elements = [ + 'Hydrogen', + 'Helium', + 'Lithium', + 'Beryllium' +]; + +elements.map(function(element) { + return element.length; +}); // esta sentença retorna o array: [8, 6, 7, 9] + +// A função regular acima pode ser escrita como a <em>arrow function</em> abaixo +elements.map((element) => { + return element.length; +}); // [8, 6, 7, 9] + +// Quando só existe um parâmetro, podemos remover os parênteses envolvendo os parâmetros: +elements.map(element => { + return element.length; +}); // [8, 6, 7, 9] + +// Quando a única sentença em uma <em>arrow function</em> é `return`, podemos remover `return` e remover +// as chaves envolvendo a sentença +elements.map(element => element.length); // [8, 6, 7, 9] + +// Neste caso, porque só precisamos da propriedade <em>length</em>, podemos usar o parâmetro de destruição (<em>destructing parameter</em>): +// Note que a <em>string</em> `"<em>length</em>"` corresponde a propriedade que queremos obter enquanto que a +// obviamente propriedade não especial `<em>lengthFooBArX</em>` é só o nome de uma variável que pode ser mudado +// para qualquer nome válido de variável que você quiser +elements.map(({ "length": lengthFooBArX }) => lengthFooBArX); // [8, 6, 7, 9] + +// Esta atribuição de parâmetro de destruição (<em>destructing parameter</em>) pode ser escrita como visto abaixo. Entretanto, note que +// não há um específico `"length"` para selecionar qual propriedade nós queremos obter. Ao invés disso, o nome literal +// da própria variável `length` é usado como a propriedade que queremos recuperar do objeto. +elements.map(({ length }) => length); // [8, 6, 7, 9]</code></pre> + +<h3 id="Sem_this_separado">Sem <code>this</code> separado</h3> + +<p>Antes das <em>arrow functions</em>, toda nova função definia seu próprio valor de <a href="/pt-BR/docs/Web/JavaScript/Reference/Operators/this">this</a> (baseado em como a função era chamada, um novo objeto no caso de um construtor, <em>undefined</em> em chamadas de funções com modo estrito (<em><a href="/pt-BR/docs/Web/JavaScript/Reference/Strict_mode">strict mode</a>)</em>, o objeto base se a função é chamada como um "método de objeto", etc.). Este comportamento é importuno com um estilo de programação orientado a objeto.</p> + +<pre class="brush: js">function Person() { + // O contrutor Person() define `<code>this`</code> como uma instância dele mesmo. + this.age = 0; + + setInterval(function growUp() { + // Em modo não estrito, a função growUp() define `this` + // como o objeto global (porque é onde growUp() é executado.), + // que é diferente ao `this` + // definido pelo construtor Person(). + this.age++; + }, 1000); +} + +var p = new Person();</pre> + +<p>No ECMAScript 3/5, este comportamento era corrigido definindo o valor em <code>this</code> à uma variável que pudesse ser encapsulada.</p> + +<pre class="brush: js">function Person() { + var that = this; + that.age = 0; + + setInterval(function growUp() { + // A chamada a função refere à variáevel `that` da qual + // o valor é o objeto esperado. + that.age++; + }, 1000); +}</pre> + +<p>Alternativamente, uma função de ligação (<a href="/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Function/bind">bound function</a>) pode ser criada para que o valor pré-atribuido à <code>this</code> seja passado para a função alvo de ligação (a função <code>growUp()</code> no exemplo acima.</p> + +<p>Uma <em>arrow function</em> não tem seu próprio <code>this;</code> o valor <code>this</code> do contexto léxico encapsulado é usado. Ex: <em>Arrow functions</em> seguem as regras normais de pesquisa de variáveis. Então, ao procurar por <code>this</code>, que não está no escopo atual elas acabam encontrando <code>this</code> no escopo encapsulado. Assim, no código a seguir, o <code>this</code> dentro da função que é passado para <code>setInterval</code> tem o mesmo valor do <code>this</code> na função lexicamente encapsulada:</p> + +<pre class="brush: js">function Person(){ + this.age = 0; + + setInterval(() => { + this.age++; // |this| corretamente se refere ao objeto Person + }, 1000); +} + +var p = new Person();</pre> + +<h4 id="Relação_com_strict_mode">Relação com <em>strict mode</em></h4> + +<p>Considerando que <code>this</code> vem do contexto léxico envolvente, as regras do modo estrito (<em><a href="/pt-BR/docs/Web/JavaScript/Reference/Strict_mode">strict mode</a></em>) em relação ao <code>this</code> são ignoradas.</p> + +<pre class="brush: js">var f = () => { 'use strict'; return this }; +f() === window; // ou o objeto global</pre> + +<p>O restante das regras do modo estrito (<em>strict mode)</em> são aplicadas normalmente.</p> + +<h4 id="Invocação_por_call_ou_apply">Invocação por call ou apply</h4> + +<p>Já que as <em>arrow functions</em> não têm o próprio <code>this</code>, os métodos <code>call()</code> ou <code>apply()</code> só podem passar parâmetros. <code>thisArg</code> é ignorado.</p> + +<pre><code>var adder = { + base: 1, + + add: function(a) { + var f = v => v + this.base; + return f(a); + }, + + addThruCall: function(a) { + var f = v => v + this.base; + var b = { + base: 2 + }; + + return f.call(b, a); + } +}; + +console.log(adder.add(1)); // Deve logar 2 +console.log(adder.addThruCall(1)); // Deve logar 2 ainda</code></pre> + +<h3 id="Sem_ligação_(binding)_de_argumentos_(arguments)">Sem ligação (<em>binding</em>) de argumentos (<code><em>arguments</em></code>)</h3> + +<p><em>Arrow functions</em> não tem o próprio objeto argumentos (<a href="/pt-BR/docs/Web/JavaScript/Reference/Functions/arguments">arguments object</a>). Assim, neste exemplo, <code>arguments</code> é simplesmente uma referência aos argumentos do escopo encapsulado:</p> + +<pre><code>var arguments = [1, 2, 3]; +var arr = () => arguments[0]; + +arr(); // 1 + +function foo(n) { + var f = () => arguments[0] + n; // ligação implícita dos argumentos de foo. arguments[0] é n + return f(); +} + +foo(3); // 6</code></pre> + +<p>Na maioria dos casos, usar parâmetros rest (<em><a href="/pt-BR/docs/Web/JavaScript/Reference/Functions/rest_parameters">rest parameters</a></em>) é uma boa alternativa a usar um objeto <code>arguments</code>.</p> + +<pre class="brush: js"><code>function foo(n) { + var f = (...args) => args[0] + n; + return f(10); +} + +foo(1); // 11</code></pre> + +<h3 id="Arrow_functions_usadas_como_métodos"><em>Arrow functions</em> usadas como métodos</h3> + +<p>Como afirmado anteriormente, expressões <em>arrow function</em> são melhores para funções que não sejam métods. Vamos ver o que acontece quando tentamos usá-las como métodos.</p> + +<pre><code>'use strict'; + +var obj = { + i: 10, + b: () => console.log(this.i, this), + c: function() { + console.log(this.i, this); + } +} + +obj.b(); // imprime undefined, Window {...} (ou o objeto global) +obj.c(); // imprime 10, Object {...}</code></pre> + +<p><em>Arrow functions</em> não tem o próprio <code>this</code>. Outro exmemplo envolvendo {{jsxref("Object.defineProperty()")}}:</p> + +<pre><code>'use strict'; + +var obj = { + a: 10 +}; + +Object.defineProperty(obj, 'b', { + get: () => { + console.log(this.a, typeof this.a, this); // undefined 'undefined' Window {...} (ou o objeto global) + return this.a + 10; // representa o objeto global 'Window', portanto 'this.a' retorna 'undefined' + } +});</code></pre> + +<h3 id="Uso_do_operador_new">Uso do operador <code>new</code></h3> + +<p>Arrow functions não podem ser usadas como construtores e lançarão um erro quando usadas com o <code>new</code>.</p> + +<h3 id="Uso_da_propriedade_prototype">Uso da propriedade <code>prototype</code></h3> + +<p><em>Arrow functions</em> não têm a propriedade <code>prototype</code>.</p> + +<pre><code>var Foo = () => {}; +console.log(Foo.prototype); // undefined</code></pre> + +<h3 id="Uso_da_palavra_chave_yield">Uso da palavra chave <code>yield</code></h3> + +<p>A palavra chave <code><a href="/pt-BR/docs/Web/JavaScript/Reference/Operators/yield">yield</a></code> não pode ser usada no corpo de uma <em>arrow function</em> (exceto quando permitido dentro de funções aninhadas dentro delas). como consequência, <em>arrow functions</em> não podem ser usadas como geradoras (<em>generators</em>).</p> + +<h2 id="Corpo_de_função">Corpo de função</h2> + +<p><em>Arrow functions</em> podem ter um corpo conciso (<em>"concise body")</em> ou o usual corpo em bloco (<em>"block body")</em>.</p> + +<p>Em um <em>concise body</em>, apenas uma expressão é especificada, a qual se torna o valor de retorno implícito. Em um <em>block body</em>, você precisa explicitamente usar a declaração de retorno, ou seja, o <code>return</code>.</p> + +<pre><code>var func = x => x * x; +// sintaxe de concise body. O "return" é implícito + +var func = (x, y) => { return x + y; }; +// Em um função com block body, é necessário um "return" explícito</code></pre> + +<h2 id="Retornando_objetos_literais">Retornando objetos literais</h2> + +<p>Tenha em mente que retornar objetos literais usando a sintaxe de corpo conciso (<em>concise body</em>) <code>params => {object:literal}</code> não funcionará como experado.</p> + +<pre><code>var func = () => { foo: 1 }; +// Chamar func() retornará undefined! + +var func = () => { foo: function() {} }; +// SyntaxError (Erro de sintaxe): a declaração da função requer um nome</code></pre> + +<p> </p> + +<p>Isto acontece porque o código dentro das chaves ({}) é convertido como uma sequência de sentenças (ex: <code>foo</code> é tratado como um título, não como uma chave num objeto literal).</p> + +<p>Se lembre de envolver o objeto literal em parênteses.</p> + +<pre><code>var func = () => ({foo: 1});</code> +</pre> + +<h2 id="Quebras_de_linha">Quebras de linha</h2> + +<p>Uma <em>arrow function</em> não pode conter uma quebra de linha entre seus parâmetros e sua flecha.</p> + +<pre><code>var func = (a, b, c) + => 1; +// SyntaxError (Erro de sintaxe): experada expressão, mas obteve '=>'</code></pre> + +<p>Entretanto, isto pode ser corrigido ao usar parênteses ou colocar a quebra de linha dentro dos argumentos como visto abaixo para garantir que o código permaneça bonito e leve.</p> + +<pre class="brush: js"><code>var func = ( + a, + b, + c +) => ( + 1 +); +// SyntaxError (erro de sintaxe) não é lançado</code></pre> + +<p> </p> + +<h2 id="Ordem_de_análise">Ordem de análise</h2> + +<p>Apesar de a flecha numa <em>arrow function</em> não ser um operador, <em>arrow functions</em> possuem regras especiais de análise que interagem diferentemente com precedência de operador (<a href="/pt-BR/docs/Web/JavaScript/Reference/Operators/Operator_Precedence">operator precedence</a>) comparadas à funções comuns.</p> + +<pre><code>let callback; + +callback = callback || function() {}; // ok + +callback = callback || () => {}; +// SyntaxError (Erro de sintaxe): argumentos inválidos de arrow-function + +callback = callback || (() => {}); // ok</code></pre> + +<p> </p> + +<h2 id="Mais_exemplos">Mais exemplos</h2> + +<pre><code>// Uma arrow function vazia retorna undefined +let empty = () => {}; + +(() => 'foobar')(); +// Retorna "foobar" +// (esta é uma Expressão de Função Invocada Imediatamente (Immediately Invoked Function Expression) +// veja 'IIFE' no glossário) + +var simple = a => a > 15 ? 15 : a; +simple(16); // 15 +simple(10); // 10 + +let max = (a, b) => a > b ? a : b; + +// Mapeamento, filtragem, ... simples de array + +var arr = [5, 6, 13, 0, 1, 18, 23]; + +var sum = arr.reduce((a, b) => a + b); +// 66 + +var even = arr.filter(v => v % 2 == 0); +// [6, 0, 18] + +var double = arr.map(v => v * 2); +// [10, 12, 26, 0, 2, 36, 46] + +// Cadeias de promessa (<em>promisse chains</em>) mais concisas +promise.then(a => { + // ... +}).then(b => { + // ... +}); + +// Arrow functions sem parâmetros que são visualmente mais fáceis de analisar +setTimeout( () => { + console.log('E aconteço antes'); + setTimeout( () => { + // deeper code + console.log('Eu aconteço depois'); + }, 1); +}, 1);</code></pre> + +<h2 id="Especificações">Especificações</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">Especificação</th> + <th scope="col">Status</th> + <th scope="col">Comentário</th> + </tr> + <tr> + <td>{{SpecName('ES2015', '#sec-arrow-function-definitions', 'Arrow Function Definitions')}}</td> + <td>{{Spec2('ES2015')}}</td> + <td>Definição inicial.</td> + </tr> + <tr> + <td>{{SpecName('ESDraft', '#sec-arrow-function-definitions', 'Arrow Function Definitions')}}</td> + <td>{{Spec2('ESDraft')}}</td> + <td> </td> + </tr> + </tbody> +</table> + +<h2 id="Compatibilidade_com_Navegadores">Compatibilidade com Navegadores</h2> + +<div class="hidden"> +<p>A tabela de compatibilidade nesta página é gerada de dados estruturados. Se você quiser contribuir com os dados, por favor verifique <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> e nos mande um <em>pull request</em>.</p> +</div> + +<div>{{Compat("javascript.functions.arrow_functions")}}</div> + +<div id="compat-mobile"> </div> |