Selon la proposition , les flèches visaient "à aborder et à résoudre plusieurs points communs douloureux du traditionnel Function Expression". Ils avaient l'intention d'améliorer les choses en liant thislexicalement et en offrant une syntaxe concise.
cependant,
- On ne peut pas toujours se lier
thislexicalement
- La syntaxe de la fonction flèche est délicate et ambiguë
Par conséquent, les fonctions fléchées créent des opportunités de confusion et d'erreurs et doivent être exclues du vocabulaire d'un programmeur JavaScript, remplacées par functionexclusivement.
Concernant lexical this
this est problématique:
function Book(settings) {
this.settings = settings;
this.pages = this.createPages();
}
Book.prototype.render = function () {
this.pages.forEach(function (page) {
page.draw(this.settings);
}, this);
};
Les fonctions fléchées visent à résoudre le problème où nous devons accéder à une propriété de l' thisintérieur d'un rappel. Il y a déjà plusieurs façons de le faire: On pourrait assigner thisà une variable, utiliser bindou utiliser le 3e argument disponible sur les Arrayméthodes d'agrégation. Pourtant, les flèches semblent être la solution de contournement la plus simple, donc la méthode pourrait être refactorisée comme ceci:
this.pages.forEach(page => page.draw(this.settings));
Cependant, considérez si le code a utilisé une bibliothèque comme jQuery, dont les méthodes se lient thisspécialement. Maintenant, il y a deux thisvaleurs à gérer:
Book.prototype.render = function () {
var book = this;
this.$pages.each(function (index) {
var $page = $(this);
book.draw(book.currentPage + index, $page);
});
};
Nous devons utiliser functionafin eachde lier thisdynamiquement. Nous ne pouvons pas utiliser de fonction de flèche ici.
Gérer plusieurs thisvaleurs peut également être source de confusion, car il est difficile de savoir de quel thisauteur parlait:
function Reader() {
this.book.on('change', function () {
this.reformat();
});
}
L'auteur avait-il réellement l'intention d'appeler Book.prototype.reformat? Ou a-t-il oublié de se lier thiset avait-il l'intention d'appeler Reader.prototype.reformat? Si nous changeons le gestionnaire en une fonction de flèche, nous nous demanderons également si l'auteur voulait la dynamique this, mais a choisi une flèche car elle tient sur une seule ligne:
function Reader() {
this.book.on('change', () => this.reformat());
}
On peut se poser la question suivante: "Est-il exceptionnel que les flèches soient parfois la mauvaise fonction à utiliser? Peut-être que si nous n'avons que rarement besoin de thisvaleurs dynamiques , il serait toujours acceptable d'utiliser des flèches la plupart du temps."
Mais demandez-vous ceci: «Serait-il« utile »de déboguer du code et de découvrir que le résultat d'une erreur a été provoqué par un« cas de bord »?» «Je préfère éviter les problèmes non seulement la plupart du temps, mais 100% du temps.
Il y a une meilleure façon: toujours utiliser function(donc thispeut toujours être lié dynamiquement), et toujours référencer thisvia une variable. Les variables sont lexicales et prennent plusieurs noms. L'affectation thisà une variable rendra vos intentions claires:
function Reader() {
var reader = this;
reader.book.on('change', function () {
var book = this;
book.reformat();
reader.reformat();
});
}
De plus, toujours assigner thisà une variable (même quand il y a une seule thisou aucune autre fonction) garantit que ses intentions restent claires même après que le code est changé.
De plus, la dynamique thisn'est guère exceptionnelle. jQuery est utilisé sur plus de 50 millions de sites Web (au moment de la rédaction de ce rapport en février 2016). Voici d'autres API liant thisdynamiquement:
- Mocha (~ 120k téléchargements hier) expose les méthodes de ses tests via
this.
- Grunt (~ 63 000 téléchargements hier) expose les méthodes de création de tâches via
this.
- Backbone (~ 22k téléchargements hier) définit les méthodes d'accès
this.
- Les API d'événement (comme les DOM) font référence à un
EventTargetavec this.
- Les API prototypées corrigées ou étendues font référence aux instances avec
this.
(Statistiques via http://trends.builtwith.com/javascript/jQuery et https://www.npmjs.com .)
Il est probable que vous thisayez déjà besoin de liaisons dynamiques .
Un lexical thisest parfois attendu, mais parfois non; tout comme une dynamique thisest parfois attendue, mais parfois non. Heureusement, il existe un meilleur moyen, qui produit et communique toujours la liaison attendue.
Concernant la syntaxe laconique
Les fonctions fléchées ont réussi à fournir une "forme syntaxique plus courte" pour les fonctions. Mais ces fonctions plus courtes vous rendront-elles plus efficaces?
Est x => x * x"plus facile à lire" que function (x) { return x * x; }? C'est peut-être le cas, car il est plus susceptible de produire une seule ligne de code courte. Accor à Dyson L'influence de la vitesse de lecture et de la longueur de ligne sur l'efficacité de la lecture à l'écran ,
Une longueur de ligne moyenne (55 caractères par ligne) semble prendre en charge une lecture efficace à des vitesses normales et rapides. Cela a produit le plus haut niveau de compréhension. . .
Des justifications similaires sont faites pour l'opérateur conditionnel (ternaire) et pour les ifinstructions sur une seule ligne .
Cependant, écrivez- vous vraiment les fonctions mathématiques simples annoncées dans la proposition ? Mes domaines ne sont pas mathématiques, donc mes sous-programmes sont rarement aussi élégants. Au contraire, je vois souvent que les fonctions fléchées dépassent une limite de colonne et se terminent par une autre ligne en raison de l'éditeur ou du guide de style, ce qui annule la «lisibilité» selon la définition de Dyson.
On pourrait se poser la question: «Que diriez-vous d'utiliser la version courte pour les fonctions courtes, lorsque cela est possible? Mais maintenant, une règle stylistique contredit une contrainte de langage: "Essayez d'utiliser la notation de fonction la plus courte possible, en gardant à l'esprit que parfois seule la notation la plus longue se liera thiscomme prévu." Cette confusion rend les flèches particulièrement susceptibles d'être utilisées à mauvais escient.
Il existe de nombreux problèmes avec la syntaxe de la fonction flèche:
const a = x =>
doSomething(x);
const b = x =>
doSomething(x);
doSomethingElse(x);
Ces deux fonctions sont syntaxiquement valides. Mais ce doSomethingElse(x);n'est pas dans le corps de b, c'est juste une déclaration de haut niveau mal indentée.
Lors de l'expansion vers la forme bloc, il n'y a plus d'implicite return, que l'on pourrait oublier de restaurer. Mais l'expression n'a peut- être été conçue que pour produire un effet secondaire, alors qui sait si une explicite returnsera nécessaire à l'avenir?
const create = () => User.create();
const create = () => {
let user;
User.create().then(result => {
user = result;
return sendEmail();
}).then(() => user);
};
const create = () => {
let user;
return User.create().then(result => {
user = result;
return sendEmail();
}).then(() => user);
};
Ce qui peut être prévu comme paramètre de repos peut être analysé en tant qu'opérateur d'étalement:
processData(data, ...results => {}) // Spread
processData(data, (...results) => {}) // Rest
L'affectation peut être confondue avec les arguments par défaut:
const a = 1;
let x;
const b = x => {}; // No default
const b = x = a => {}; // "Adding a default" instead creates a double assignment
const b = (x = a) => {}; // Remember to add parens
Les blocs ressemblent à des objets:
(id) => id // Returns `id`
(id) => {name: id} // Returns `undefined` (it's a labeled statement)
(id) => ({name: id}) // Returns an object
Qu'est-ce que ça veut dire?
() => {}
L'auteur avait-il l'intention de créer un no-op, ou une fonction qui renvoie un objet vide? (Dans cet esprit, devrions-nous jamais placer {après =>? Devrions-nous nous limiter à la syntaxe d'expression uniquement? Cela réduirait davantage la fréquence des flèches.)
=>ressemble <=et >=:
x => 1 ? 2 : 3
x <= 1 ? 2 : 3
if (x => 1) {}
if (x >= 1) {}
Pour invoquer une expression de fonction flèche immédiatement, il faut placer ()à l'extérieur, mais placer ()à l'intérieur est valide et peut être intentionnel.
(() => doSomething()()) // Creates function calling value of `doSomething()`
(() => doSomething())() // Calls the arrow function
Bien que, si l'on écrit (() => doSomething()());avec l'intention d'écrire une expression de fonction immédiatement invoquée, rien ne se passera.
Il est difficile de prétendre que les fonctions fléchées sont "plus compréhensibles" compte tenu des cas ci-dessus. On pourrait apprendre toutes les règles spéciales requises pour utiliser cette syntaxe. ça en vaut vraiment la peine?
La syntaxe de functionest généralisée sans exception. Utiliser functionexclusivement signifie que le langage lui-même empêche d'écrire du code déroutant. Pour écrire des procédures qui doivent être comprises syntaxiquement dans tous les cas, je choisis function.
Concernant une ligne directrice
Vous demandez une ligne directrice qui doit être "claire" et "cohérente". L'utilisation des fonctions fléchées aboutira finalement à un code syntaxiquement valide et logiquement invalide, les deux formes de fonction étant entrelacées, de manière significative et arbitraire. Par conséquent, j'offre ce qui suit:
Directive pour la notation des fonctions dans ES6:
- Créez toujours des procédures avec
function.
- Attribuez toujours
thisà une variable. Ne pas utiliser () => {}.
Fixed this bound to scope at initialisationcomme une limitation?