aboutsummaryrefslogtreecommitdiff
path: root/files/pt-br/web/javascript/reference/functions/arrow_functions/index.html
blob: b550d633e14f387c3c6dc8f55293aad4277b3884 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
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) =&gt; { statements }
(param1, param2, …, paramN) =&gt; expression
// equivalente a: =&gt; { return expression; }

// Parênteses são opcionais quando só há um nome de parâmetro:
(singleParam) =&gt; { statements }
singleParam =&gt; { statements }

// A lista de parâmetros para uma função sem parâmetros deve ser escrita com um par de parênteses.
() =&gt; { 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 =&gt; ({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) =&gt; { statements }
(param1 = defaultValue1, param2, …, paramN = defaultValueN) =&gt; { 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}) =&gt; 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) =&gt; {
  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 =&gt; {
  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 =&gt; 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 }) =&gt; 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 }) =&gt; 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(() =&gt; {
    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 = () =&gt; { '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 =&gt; v + this.base;
    return f(a);
  },

  addThruCall: function(a) {
    var f = v =&gt; 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 = () =&gt; arguments[0];

arr(); // 1

function foo(n) {
  var f = () =&gt; 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) =&gt; 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: () =&gt; 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 exemplo envolvendo {{jsxref("Object.defineProperty()")}}:</p>

<pre><code>'use strict';

var obj = {
  a: 10
};

Object.defineProperty(obj, 'b', {
  get: () =&gt; {
    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 = () =&gt; {};
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 =&gt; x * x;
// sintaxe de concise body. O "return" é implícito

var func = (x, y) =&gt; { 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 =&gt; {object:literal}</code> não funcionará como esperado.</p>

<pre><code>var func = () =&gt; { foo: 1 };
// Chamar func() retornará undefined!

var func = () =&gt; { 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 = () =&gt; ({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)
           =&gt; 1;
// SyntaxError (Erro de sintaxe): esperada expressão, mas obteve '=&gt;'</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
) =&gt; (
  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 || () =&gt; {};
// SyntaxError (Erro de sintaxe): argumentos inválidos de arrow-function

callback = callback || (() =&gt; {});    // ok</code></pre>

<p> </p>

<h2 id="Mais_exemplos">Mais exemplos</h2>

<pre><code>// Uma arrow function vazia retorna undefined
let empty = () =&gt; {};

(() =&gt; 'foobar')();
// Retorna "foobar"
// (esta é uma Expressão de Função Invocada Imediatamente (Immediately Invoked Function Expression)
// veja 'IIFE' no glossário)

var simple = a =&gt; a &gt; 15 ? 15 : a;
simple(16); // 15
simple(10); // 10

let max = (a, b) =&gt; a &gt; b ? a : b;

// Mapeamento, filtragem, ... simples de array

var arr = [5, 6, 13, 0, 1, 18, 23];

var sum = arr.reduce((a, b) =&gt; a + b);
// 66

var even = arr.filter(v =&gt; v % 2 == 0);
// [6, 0, 18]

var double = arr.map(v =&gt; v * 2);
// [10, 12, 26, 0, 2, 36, 46]

// Cadeias de promessa (<em>promisse chains</em>) mais concisas
promise.then(a =&gt; {
  // ...
}).then(b =&gt; {
  // ...
});

// Arrow functions sem parâmetros que são visualmente mais fáceis de analisar
setTimeout( () =&gt; {
  console.log('E aconteço antes');
  setTimeout( () =&gt; {
    // 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>