--- 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 ---
{{jsSidebar("Functions")}}

Una funzione a freccia ha una sintassi più compatta rispetto alla notazione a funzione e non associa i propri thisargumentssuper 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.

Sintassi

Sintassi di base

(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; }

Sintassi avanzata

// 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.

Descrizione

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.

Funzioni più corte

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]

Mancato binding di 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();

Relazione con strict mode

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.

Invocazione attraverso call or apply

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

Mancato binding di arguments

Le funzioni a freccia non definiscono il proprio  argumentsPerciò, 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

Funzioni a freccia come metodi

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'
  }
});

Uso dell'operatore new 

Le funzioni a freccia non possono essere usate come costruttori, ed emetteranno un errore se usate con new.

Uso di 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.

Body della funzione

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

Restituire object literals

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 });

Newline

Le funzioni a freccia non possono contenere un newline tra i parametri e la freccia.

var func = ()
           => 1; // SyntaxError: expected expression, got '=>'

Ordine di parsing

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

Altri esempi

// 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);

 

 

 

Specifiche

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')}}  

Compatibilità dei Browser 

{{CompatibilityTable}}
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)}}

Note specifiche per Firefox

Vedi anche