Le "funzioni freccia" e le "funzioni" sono equivalenti / intercambiabili?
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
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
thisoarguments. - 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:
- Quando dovrei usare le funzioni Arrow in ECMAScript 6?
- Le funzioni freccia di ES6 hanno i propri argomenti o no?
- Quali sono le differenze (se presenti) tra le funzioni freccia ES6 e le funzioni associate a Function.prototype.bind?
- Come utilizzare le funzioni freccia (campi di classi pubbliche) come metodi di classe?
Ulteriori risorse:
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é:
Non hanno
thisUtilizza lo "scoping lessicale" per capire quale
thisdovrebbe essere il valore di " ". In parole semplici, scoping lessicale utilizza "this" dall'interno del corpo della funzione.Non hanno
argumentsLe 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"Non possono essere utilizzati con
newLe funzioni freccia non possono essere costruttrici perché non hanno una proprietà prototipo.
Quando utilizzare la funzione freccia e quando no:
- Non utilizzare per aggiungere una funzione come proprietà nell'oggetto letterale perché non possiamo accedervi.
- Le espressioni di funzione sono le migliori per i metodi oggetto. Arrow funzioni sono i migliori per le richiamate o metodi come
map,reduceoforEach. - Usa le dichiarazioni di funzione per le funzioni che chiameresti per nome (perché sono sollevate).
- Usa le funzioni freccia per i callback (perché tendono ad essere più concisi).
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