Le "funzioni freccia" e le "funzioni" sono equivalenti / intercambiabili?

Dec 19 2015

Le funzioni freccia in ES2015 forniscono una sintassi più concisa.

  • Posso sostituire tutte le mie dichiarazioni / espressioni di funzione con funzioni freccia ora?
  • A cosa devo prestare attenzione?

Esempi:

Funzione costruttore

function User(name) {
  this.name = name;
}

// vs

const User = name => {
  this.name = name;
};

Metodi prototipo

User.prototype.getName = function() {
  return this.name;
};

// vs

User.prototype.getName = () => this.name;

Metodi oggetto (letterali)

const obj = {
  getName: function() {
    // ...
  }
};

// vs

const obj = {
  getName: () => {
    // ...
  }
};

Richiami

setTimeout(function() {
  // ...
}, 500);

// vs

setTimeout(() => {
  // ...
}, 500);

Funzioni variadiche

function sum() {
  let args = [].slice.call(arguments);
  // ...
}

// vs
const sum = (...args) => {
  // ...
};

Risposte

817 FelixKling Dec 19 2015 at 00:58

tl; dr: No! Le funzioni freccia e le dichiarazioni / espressioni di funzione non sono equivalenti e non possono essere sostituite ciecamente.
Se la funzione che si desidera sostituire non non usare this, argumentse non viene chiamato con new, allora sì.


Come tante volte: dipende . Le funzioni freccia hanno un comportamento diverso rispetto alle dichiarazioni / espressioni di funzione, quindi diamo prima un'occhiata alle differenze:

1. Lessico thisearguments

Le funzioni freccia non hanno le proprie thiso argumentsassociazioni. Invece, questi identificatori vengono risolti nell'ambito lessicale come qualsiasi altra variabile. Ciò significa che all'interno di una funzione freccia thise si argumentsriferiscono ai valori di thise argumentsnell'ambiente la funzione freccia è definita in (cioè "fuori" dalla funzione freccia):

// Example using a function expression
function createObject() {
  console.log('Inside `createObject`:', this.foo);
  return {
    foo: 42,
    bar: function() {
      console.log('Inside `bar`:', this.foo);
    },
  };
}

createObject.call({foo: 21}).bar(); // override `this` inside createObject

// Example using a arrow function
function createObject() {
  console.log('Inside `createObject`:', this.foo);
  return {
    foo: 42,
    bar: () => console.log('Inside `bar`:', this.foo),
  };
}

createObject.call({foo: 21}).bar(); // override `this` inside createObject

Nel caso dell'espressione di funzione, si thisriferisce all'oggetto creato all'interno di createObject. Nel caso funzione freccia, thissi riferisce al thisdi createObjectsé.

Ciò rende le funzioni delle frecce utili se è necessario accedere thisall'ambiente corrente:

// currently common pattern
var that = this;
getData(function(data) {
  that.data = data;
});

// better alternative with arrow functions
getData(data => {
  this.data = data;
});

Notare che questo significa anche che non è possibile impostare una funzione freccia thiscon .bindo .call.

Se non hai molta familiarità this, considera la lettura

2. Le funzioni freccia non possono essere chiamate con new

ES2015 distingue tra funzioni che possono essere richiamate e funzioni che possono essere costruite . Se una funzione è costruibile, può essere chiamata con new, ie new User(). Se una funzione è richiamabile, può essere chiamata senza new(cioè chiamata di funzione normale).

Le funzioni create tramite dichiarazioni / espressioni di funzione sono sia costruibili che richiamabili.
Le funzioni (e i metodi) delle frecce sono solo richiamabili. classi costruttori sono solo costruibili.

Se stai cercando di chiamare una funzione non richiamabile o di costruire una funzione non costruibile, riceverai un errore di runtime.


Sapendo questo, possiamo affermare quanto segue.

Sostituibile:

  • Funzioni che non usano thiso arguments.
  • Funzioni utilizzate con .bind(this)

Non sostituibile:

  • Funzioni del costruttore
  • Funzione / metodi aggiunti a un prototipo (perché di solito usano this)
  • Funzioni variadiche (se usano arguments(vedi sotto))

Diamo uno sguardo più da vicino a questo usando i tuoi esempi:

Funzione costruttore

Questo non funzionerà perché le funzioni freccia non possono essere chiamate con new. Continua a usare una dichiarazione / espressione di funzione o usa class.

Metodi prototipo

Molto probabilmente no, perché i metodi del prototipo di solito usano thisper accedere all'istanza. Se non lo usano this, puoi sostituirlo. Tuttavia, se ti interessa principalmente la sintassi concisa, usa classla sintassi del metodo conciso:

class User {
  constructor(name) {
    this.name = name;
  }
  
  getName() {
    return this.name;
  }
}

Metodi oggetto

Allo stesso modo per i metodi in un oggetto letterale. Se il metodo desidera fare riferimento all'oggetto stesso tramite this, continuare a utilizzare le espressioni di funzione o utilizzare la nuova sintassi del metodo:

const obj = {
  getName() {
    // ...
  },
};

Richiami

Dipende. Dovresti assolutamente sostituirlo se stai thisusando un alias esterno o stai usando .bind(this):

// old
setTimeout(function() {
  // ...
}.bind(this), 500);

// new
setTimeout(() => {
  // ...
}, 500);

Ma: se il codice che chiama il callback si imposta esplicitamente thissu un valore specifico, come spesso accade con i gestori di eventi, specialmente con jQuery, e il callback usa this(o arguments), non puoi usare una funzione freccia!

Funzioni variadiche

Poiché le funzioni freccia non hanno le proprie arguments, non è possibile sostituirle semplicemente con una funzione freccia. Tuttavia, ES2015 introduce un'alternativa all'utilizzo arguments: il parametro rest .

// old
function sum() {
  let args = [].slice.call(arguments);
  // ...
}

// new
const sum = (...args) => {
  // ...
};

Domanda correlata:

Ulteriori risorse:

17 Ashutosh Jan 10 2020 at 03:22

Funzioni freccia => la migliore funzionalità ES6 finora. Sono un'aggiunta tremendamente potente a ES6, che uso costantemente.

Aspetta, non puoi usare la funzione freccia ovunque nel tuo codice, non funzionerà in tutti i casi come thisdove le funzioni freccia non sono utilizzabili. Senza dubbio, la funzione freccia è una grande aggiunta che porta la semplicità del codice.

Ma non è possibile utilizzare una funzione freccia quando è richiesto un contesto dinamico: definire metodi, creare oggetti con costruttori, ottenere l'obiettivo da questo quando si gestiscono eventi.

Le funzioni freccia NON dovrebbero essere utilizzate perché:

  1. Non hanno this

    Utilizza lo "scoping lessicale" per capire quale thisdovrebbe essere il valore di " ". In parole semplici, scoping lessicale utilizza " this" dall'interno del corpo della funzione.

  2. Non hanno arguments

    Le funzioni freccia non hanno un argumentsoggetto. Ma la stessa funzionalità può essere ottenuta utilizzando i parametri di riposo.

    let sum = (...args) => args.reduce((x, y) => x + y, 0) sum(3, 3, 1) // output - 7 "

  3. Non possono essere utilizzati con new

    Le funzioni freccia non possono essere costruttrici perché non hanno una proprietà prototipo.

Quando utilizzare la funzione freccia e quando no:

  1. Non utilizzare per aggiungere una funzione come proprietà nell'oggetto letterale perché non possiamo accedervi.
  2. Le espressioni di funzione sono le migliori per i metodi oggetto. Arrow funzioni sono i migliori per le richiamate o metodi come map, reduceo forEach.
  3. Usa le dichiarazioni di funzione per le funzioni che chiameresti per nome (perché sono sollevate).
  4. Usa le funzioni freccia per i callback (perché tendono ad essere più concisi).
2 toddmo May 16 2020 at 08:56

Per utilizzare le funzioni freccia con function.prototype.call, ho creato una funzione di supporto sul prototipo dell'oggetto:

  // Using
  // @func = function() {use this here} or This => {use This here}
  using(func) {
    return func.call(this, this);
  }

utilizzo

  var obj = {f:3, a:2}
  .using(This => This.f + This.a) // 5

modificare

Non hai bisogno di un aiuto. Potresti fare:

var obj = {f:3, a:2}
(This => This.f + This.a).call(undefined, obj); // 5