Les «fonctions fléchées» et les «fonctions» sont-elles équivalentes / interchangeables?
Les fonctions de flèche dans ES2015 fournissent une syntaxe plus concise.
- Puis-je remplacer toutes mes déclarations / expressions de fonction par des fonctions fléchées maintenant?
- À quoi dois-je faire attention?
Exemples:
Fonction constructeur
function User(name) {
this.name = name;
}
// vs
const User = name => {
this.name = name;
};
Méthodes de prototype
User.prototype.getName = function() {
return this.name;
};
// vs
User.prototype.getName = () => this.name;
Méthodes objet (littérales)
const obj = {
getName: function() {
// ...
}
};
// vs
const obj = {
getName: () => {
// ...
}
};
Rappels
setTimeout(function() {
// ...
}, 500);
// vs
setTimeout(() => {
// ...
}, 500);
Fonctions variadiques
function sum() {
let args = [].slice.call(arguments);
// ...
}
// vs
const sum = (...args) => {
// ...
};
Réponses
tl; dr: Non! Les fonctions fléchées et les déclarations / expressions de fonction ne sont pas équivalentes et ne peuvent pas être remplacées aveuglément.
Si la fonction que vous souhaitez remplacer ne pas utiliser this
, arguments
et n'est pas appelé avec new
, alors oui.
Comme souvent: cela dépend . Les fonctions fléchées ont un comportement différent des déclarations / expressions de fonction, alors examinons d'abord les différences:
1. Lexique this
etarguments
Les fonctions fléchées n'ont pas les leurs this
ni arguments
les leurs. Au lieu de cela, ces identificateurs sont résolus dans la portée lexicale comme toute autre variable. Cela signifie qu'à l'intérieur d'une fonction de flèche, this
et se arguments
référer aux valeurs de this
et arguments
dans l'environnement, la fonction de flèche est définie dans (c'est-à-dire "à l'extérieur" de la fonction de flèche):
// 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
Dans le cas de l'expression de fonction, this
fait référence à l'objet qui a été créé dans le createObject
. Dans le cas de la fonction flèche, se this
réfère à lui this
- createObject
même.
Cela rend les fonctions fléchées utiles si vous devez accéder à l' this
environnement actuel:
// currently common pattern
var that = this;
getData(function(data) {
that.data = data;
});
// better alternative with arrow functions
getData(data => {
this.data = data;
});
Notez que cela signifie également qu'il n'est pas possible de définir une fonction de flèche this
avec .bind
ou .call
.
Si vous n'êtes pas très familier avec this
, pensez à lire
2. Les fonctions fléchées ne peuvent pas être appelées avec new
ES2015 établit une distinction entre les fonctions qui appellent mesure et les fonctions qui sont construire en mesure. Si une fonction est constructible, elle peut être appelée avec new
, ie new User()
. Si une fonction est appelable, elle peut être appelée sans new
(c'est-à-dire appel de fonction normal).
Les fonctions créées par des déclarations / expressions de fonction sont à la fois constructibles et appelables.
Les fonctions (et méthodes) fléchées sont uniquement appelables.
class
les constructeurs sont uniquement constructibles.
Si vous essayez d'appeler une fonction non appelable ou de construire une fonction non constructible, vous obtiendrez une erreur d'exécution.
Sachant cela, nous pouvons affirmer ce qui suit.
Remplaçable:
- Fonctions qui n'utilisent pas
this
ouarguments
. - Fonctions utilisées avec
.bind(this)
Non remplaçable:
- Fonctions du constructeur
- Fonction / méthodes ajoutées à un prototype (car elles l'utilisent généralement
this
) - Fonctions variadiques (si elles utilisent
arguments
(voir ci-dessous))
Regardons cela de plus près en utilisant vos exemples:
Fonction constructeur
Cela ne fonctionnera pas car les fonctions fléchées ne peuvent pas être appelées avec new
. Continuez à utiliser une déclaration / expression de fonction ou utilisez class
.
Méthodes de prototype
Très probablement pas, car les méthodes prototypes utilisent généralement this
pour accéder à l'instance. S'ils ne l'utilisent pas this
, vous pouvez le remplacer. Cependant, si vous vous souciez principalement de la syntaxe concise, utilisez class
avec sa syntaxe de méthode concise:
class User {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
Méthodes objet
De même pour les méthodes dans un objet littéral. Si la méthode souhaite référencer l'objet lui-même via this
, continuez à utiliser des expressions de fonction ou utilisez la nouvelle syntaxe de méthode:
const obj = {
getName() {
// ...
},
};
Rappels
Ça dépend. Vous devez absolument le remplacer si vous aliasez l'extérieur this
ou utilisez .bind(this)
:
// old
setTimeout(function() {
// ...
}.bind(this), 500);
// new
setTimeout(() => {
// ...
}, 500);
Mais: Si le code qui appelle le callback définit explicitement this
une valeur spécifique, comme c'est souvent le cas avec les gestionnaires d'événements, en particulier avec jQuery, et que le callback utilise this
(ou arguments
), vous ne pouvez pas utiliser une fonction de flèche!
Fonctions variadiques
Étant donné que les fonctions fléchées n'ont pas les leurs arguments
, vous ne pouvez pas simplement les remplacer par une fonction fléchée. Cependant, ES2015 introduit une alternative à l'utilisation arguments
: le paramètre rest .
// old
function sum() {
let args = [].slice.call(arguments);
// ...
}
// new
const sum = (...args) => {
// ...
};
Question connexe:
- Quand dois-je utiliser les fonctions Arrow dans ECMAScript 6?
- Les fonctions fléchées ES6 ont-elles leurs propres arguments ou non?
- Quelles sont les différences (le cas échéant) entre les fonctions fléchées ES6 et les fonctions liées à Function.prototype.bind?
- Comment utiliser les fonctions fléchées (champs de classe publics) comme méthodes de classe?
Autres ressources:
Fonctions fléchées => meilleure fonctionnalité ES6 à ce jour. Ils sont un ajout extrêmement puissant à ES6, que j'utilise constamment.
Attendez, vous ne pouvez pas utiliser la fonction fléchée partout dans votre code, elle ne fonctionnera pas dans tous les cas, comme this
lorsque les fonctions fléchées ne sont pas utilisables. Sans aucun doute, la fonction flèche est un excellent ajout, elle apporte la simplicité du code.
Mais vous ne pouvez pas utiliser une fonction de flèche lorsqu'un contexte dynamique est requis: définir des méthodes, créer des objets avec des constructeurs, obtenir la cible à partir de cela lors de la gestion des événements.
Les fonctions fléchées ne doivent PAS être utilisées car:
Ils n'ont pas
this
Il utilise la «portée lexicale» pour déterminer quelle
this
devrait être la valeur de « ». Dans la portée lexicale de mots simples, il utilise «this
» de l'intérieur du corps de la fonction.Ils n'ont pas
arguments
Les fonctions fléchées n'ont pas d'
arguments
objet. Mais la même fonctionnalité peut être obtenue en utilisant des paramètres de repos.let sum = (...args) => args.reduce((x, y) => x + y, 0)
sum(3, 3, 1) // output - 7
»Ils ne peuvent pas être utilisés avec
new
Les fonctions fléchées ne peuvent pas être des constructeurs car elles n'ont pas de propriété prototype.
Quand utiliser la fonction fléchée et quand non:
- Ne pas utiliser pour ajouter une fonction en tant que propriété dans un objet littéral car nous ne pouvons pas y accéder.
- Les expressions de fonction sont les meilleures pour les méthodes objet. Catégorie fonctions sont les meilleurs pour callbacks ou des méthodes telles que
map
,reduce
ouforEach
. - Utilisez des déclarations de fonction pour les fonctions que vous appelleriez par leur nom (car elles sont hissées).
- Utilisez les fonctions fléchées pour les rappels (car elles ont tendance à être terser).
Pour utiliser les fonctions fléchées avec function.prototype.call
, j'ai créé une fonction d'assistance sur le prototype d'objet:
// Using
// @func = function() {use this here} or This => {use This here}
using(func) {
return func.call(this, this);
}
usage
var obj = {f:3, a:2}
.using(This => This.f + This.a) // 5
Éditer
Vous n'avez pas besoin d'aide. Vous pourriez faire:
var obj = {f:3, a:2}
(This => This.f + This.a).call(undefined, obj); // 5