--- title: Funzioni a freccia slug: Web/JavaScript/Reference/Functions/Arrow_functions tags: - ECMAScript6 - Funzioni - Intermediate - JavaScript - Reference translation_of: Web/JavaScript/Reference/Functions/Arrow_functions original_slug: Web/JavaScript/Reference/Functions_and_function_scope/Arrow_functions ---
Una funzione a freccia ha una sintassi più compatta rispetto alla notazione a funzione e non associa i propri this
, arguments, super o new.target. Le funzioni a freccia sono sempre anonime. Questa notazione è maggiormente indicata per le funzioni che non sono metodi, e non possono essere usate come costruttori.
(param1, param2, …, paramN) => { statements } (param1, param2, …, paramN) => expression // equivalente a: (param1, param2, …, paramN) => { return expression; } // Le Parentesi sono opzionali se è presente un solo parametro: (singleParam) => { statements } singleParam => { statements } // Una funzione senza parametri richiede comunque le parentesi: () => { statements } () => expression // equivalente a: () => { return expression; }
// Il body tra parentesi indica la restituzione di un oggetto: params => ({foo: bar}) // Sono supportati ...rest e i parametri di default (param1, param2, ...rest) => { statements } (param1 = defaultValue1, param2, …, paramN = defaultValueN) => { statements } // Si può anche destrutturare all'interno della lista dei parametri var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c; f(); // 6
Esempi dettagliati di sintassi sono disponibili qui.
Vedi anche "ES6 In Depth: Arrow functions" su hacks.mozilla.org.
L'introduzione delle funzioni a freccia è stata influenzata da due fattori: sintassi più compatta e la non associazione di this
.
In alcuni pattern, è meglio avere funzioni più corte. Per comparazione:
var materials = [ "Hydrogen", "Helium", "Lithium", "Beryllium" ]; materials.map(function(material) { return material.length; });// [8, 6, 7, 9]
materials.map((material) => {return material.length; }); // [8, 6, 7, 9]
materials.map(material => material.length); // [8, 6, 7, 9]
this
Prima delle funzioni a freccia, ogni nuova funzione definiva il proprio this
(un nuovo oggetto nel caso di un costruttore, undefined se una funzione viene chiamata in strict mode, l'oggetto di contesto se la funzione viene chiamata come "metodo", etc.). Questo è risultato fastidioso in uno stile di programmazione orientato agli oggetti.
function Person() { // The Person() constructor defines `this` as an instance of itself. this.age = 0; setInterval(function growUp() { // In non-strict mode, the growUp() function defines `this` // as the global object, which is different from the `this` // defined by the Person() constructor. this.age++; }, 1000); } var p = new Person();
In ECMAScript 3/5, questo problema veniva aggirato assegnando il valore this a una variabile.
function Person() { var that = this; that.age = 0; setInterval(function growUp() { // The callback refers to the `that` variable of which // the value is the expected object. that.age++; }, 1000); }
In alternativa, poteva essere usato Function.prototype.bind per assegnare il valore corretto di this da usare nella funzione growUp()
.
Una funziona a freccia invece non crea il proprio this
, e quindi this
mantiene il significato che aveva all'interno dello scope genitore. Perciò il codice seguente funziona come ci si aspetta.
function Person(){ this.age = 0; setInterval(() => { this.age++; // |this| properly refers to the person object }, 1000); } var p = new Person();
Poiché this
è lessicale, le regole di strict mode relative a this
sono semplicemente ignorate.
var f = () => {'use strict'; return this}; f() === window; // o l'oggetto globale
Il resto delle regole si applica normalmente.
Poiché this
non viene assegnato nelle funzioni a freccia, i metodi call()
o apply()
possono passare solo come argomenti; this
viene ignorato:
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)); // This would log to 2 console.log(adder.addThruCall(1)); // This would log to 2 still
arguments
Le funzioni a freccia non definiscono il proprio arguments.
Perciò, arguments
è semplicemente una reference alla variabile nello scope genitore.
var arguments = 42; var arr = () => arguments; arr(); // 42 function foo() { var f = (i) => arguments[0]+i; // foo's implicit arguments binding return f(2); } foo(1); // 3
Le funzioni a freccia non hanno il proprio oggetto arguments
, ma in molti casi i parametri rest rappresentano una valida alternativa:
function foo() { var f = (...args) => args[0]; return f(2); } foo(1); // 2
Come già citato, le funzioni a freccia sono sconsigliate come metodi. Vediamo cosa succede quando proviamo a usarle:
'use strict'; var obj = { i: 10, b: () => console.log(this.i, this), c: function() { console.log( this.i, this) } } obj.b(); // prints undefined, Window obj.c(); // prints 10, Object {...}
Le funzioni a freccia non definiscono ("bind") il proprio this
. un altro esempio usando {{jsxref("Object.defineProperty()")}}:
'use strict'; var obj = { a: 10 }; Object.defineProperty(obj, "b", { get: () => { console.log(this.a, typeof this.a, this); return this.a+10; // represents global object 'Window', therefore 'this.a' returns 'undefined' } });
new
Le funzioni a freccia non possono essere usate come costruttori, ed emetteranno un errore se usate con new
.
yield
La keyword yield
non deve essere usata nel body di una funzione a freccia (eccetto quando permesso in eventuali funzioni al loro interno). Conseguentemente, le funzioni a freccia non possono essere usate come generatori.
Le funzioni a freccia possono avere un "body conciso" o l'usuale "blocco body".
Nel primo caso è necessaria solo un'espressione, e il return è implicito. Nel secondo caso, devi usare esplicitamente return
.
var func = x => x * x; // concise syntax, implied "return" var func = (x, y) => { return x + y; }; // with block body, explicit "return" needed
Tieni a mente che restituire oggetti letterali usando la sintassi concisa params => {object:literal}
non funzionerà:
var func = () => { foo: 1 }; // Calling func() returns undefined! var func = () => { foo: function() {} }; // SyntaxError: function statement requires a name
Questo perché il codice all'interno delle parentesi graffe ({}) è processato come una sequenza di statement (i.e. foo
è trattato come un label, non come una key di un oggetto).
Tuttavia, è sufficente racchiudere l'oggetto tra parentesi tonde:
var func = () => ({ foo: 1 });
Le funzioni a freccia non possono contenere un newline tra i parametri e la freccia.
var func = () => 1; // SyntaxError: expected expression, got '=>'
La freccia in una funziona a freccia non è un'operatore, ma le funzioni a freccia hanno delle regole di parsing specifiche che interagiscono differentemente con la precedenza degli operatori, rispetto alle funzioni normali.
let callback; callback = callback || function() {}; // ok callback = callback || () => {}; // SyntaxError: invalid arrow-function arguments callback = callback || (() => {}); // ok
// Una funzione a freccie vuota restituisce undefined let empty = () => {}; (() => "foobar")() // IIFE, restituisce "foobar" var simple = a => a > 15 ? 15 : a; simple(16); // 15 simple(10); // 10 let max = (a, b) => a > b ? a : b; // Più semplice gestire filtering, mapping, ... di 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] // Le catene di promise sono più concise promise.then(a => { // ... }).then(b => { // ... }); // le funzioni a freccia senza parametri sono più semplici da visualizzare setTimeout( _ => { console.log("I happen sooner"); setTimeout( _ => { // deeper code console.log("I happen later"); }, 1); }, 1);
Specification | Status | Comment |
---|---|---|
{{SpecName('ES6', '#sec-arrow-function-definitions', 'Arrow Function Definitions')}} | {{Spec2('ES6')}} | Initial definition. |
{{SpecName('ESDraft', '#sec-arrow-function-definitions', 'Arrow Function Definitions')}} | {{Spec2('ESDraft')}} |
Feature | Chrome | Firefox (Gecko) | Edge | IE | Opera | Safari |
---|---|---|---|---|---|---|
Basic support | {{CompatChrome(45.0)}} | {{CompatGeckoDesktop("22.0")}} | {{CompatVersionUnknown}} |
{{CompatNo}} |
{{CompatOpera(32)}} | {{CompatSafari(10.0)}} |
Feature | Android | Android Webview | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile | Chrome for Android |
---|---|---|---|---|---|---|---|
Basic support | {{CompatNo}} | {{CompatChrome(45.0)}} | {{CompatGeckoMobile("22.0")}} | {{CompatNo}} | {{CompatNo}} | {{CompatSafari(10.0)}} | {{CompatChrome(45.0)}} |
"use strict";
è ora obbligatorio.this
in modo lessicale.\n
) era erroneamente accettato dopo i parametri della funzione. Questo è stato risolto in conformità alle specifiche ES6 e codice come () \n => {}
emetterà un {{jsxref("SyntaxError")}} in questa versione e successive.