J'ai lu un tas de code react
et je vois des choses comme ça que je ne comprends pas:
handleChange = field => e => {
e.preventDefault();
/// Do something here
}
Comprendre les syntaxes disponibles des fonctions de flèches vous permettra de comprendre le comportement qu’elles présentent lorsqu’elles sont chaînées, comme dans les exemples que vous avez fournis.
Lorsqu'une fonction de flèche est écrite sans accolades de bloc, avec ou sans plusieurs paramètres, l'expression constituant le corps de la fonction est implicitement est renvoyée. Dans votre exemple, cette expression est une autre fonction de flèche.
No arrow funcs Implicitly return `e=>{…}` Explicitly return `e=>{…}`
---------------------------------------------------------------------------------
function (field) { | field => e => { | field => {
return function (e) { | | return e => {
e.preventDefault() | e.preventDefault() | e.preventDefault()
} | | }
} | } | }
Un autre avantage de l’écriture de fonctions anonymes à l’aide de la syntaxe flèche est qu’elles sont liées lexicalement à la portée dans laquelle elles sont définies. De 'Fonctions de flèche' sur MDN }:
Une expression de fonction flèche a une syntaxe plus courte comparée à expressions de fonction et lie lexicalement la valeur ceci . Les fonctions de flèche sont toujours anonyme .
Ceci est particulièrement pertinent dans votre exemple, étant donné qu’il provient d’une application reactjs . Comme l'a souligné @naomik, dans React, vous accédez souvent à un fonctions membres du composant } à l'aide de this
. Par exemple:
Unbound Explicitly bound Implicitly bound
------------------------------------------------------------------------------
function (field) { | function (field) { | field => e => {
return function (e) { | return function (e) { |
this.setState(...) | this.setState(...) | this.setState(...)
} | }.bind(this) |
} | }.bind(this) | }
Un conseil général: si vous avez du mal à comprendre la nouvelle syntaxe JS et son compilation, vous pouvez vérifier babel . Par exemple, copier votre code dans babel et sélectionner le préréglage es2015 donnera un résultat comme celui-ci
handleChange = function handleChange(field) {
return function (e) {
e.preventDefault();
// Do something here
};
};
Pensez-y comme ceci: chaque fois que vous voyez une flèche, vous la remplacez par function
.function parameters
sont définis avant la flèche.
Donc dans votre exemple:
field => // function(field){}
e => { e.preventDefault(); } // function(e){e.preventDefault();}
et puis ensemble:
function (field) {
return function (e) {
e.preventDefault();
};
}
À partir de la documentation :
// Basic syntax:
(param1, param2, paramN) => { statements }
(param1, param2, paramN) => expression
// equivalent to: => { return expression; }
// Parentheses are optional when there's only one argument:
singleParam => { statements }
singleParam => expression
Bref et simple ????
C'est une fonction qui renvoie une autre fonction écrite de manière abrégée.
const handleChange = field => e => {
e.preventDefault()
// Do something here
}
// is equal to
function handleChange(field) {
return function(e) {
e.preventDefault()
// Do something here
}
}
Pourquoi les gens le font
Avez-vous fait face lorsque vous avez besoin d’écrire une fonction qui peut être personnalisée? Ou vous devez écrire une fonction de rappel qui a des paramètres fixes (arguments), variables? Si votre réponse "yes" alors c'est la façon de le faire.
Par exemple, nous avons un button
avec rappel onClick. Et nous devons passer id
à la fonction, mais onClick
n'accepte qu'un paramètre event
, nous ne pouvons pas passer de paramètres supplémentaires dans les cas suivants:
const handleClick = (event, id) {
event.preventDefault()
// Dispatch some delete action by passing record id
}
Ça ne marchera pas!
Par conséquent, nous créons une fonction qui renverra une autre fonction avec son propre champ de variables sans aucune variable globale, car les variables globales sont mauvaises ????.
En dessous de la fonction handleClick(props.id)}
sera appelée et retournera une fonction et aura id
dans son étendue! Peu importe le nombre de fois où vous appuierez, les identifiants ne se modifieront pas, ils sont totalement isolés.
const handleClick = id => event {
event.preventDefault()
// Dispatch some delete action by passing record id
}
const Confirm = props => (
<div>
<h1>Are you sure to delete?</h1>
<button onClick={handleClick(props.id)}>
Delete
</button>
</div
)
L'exemple de votre question est celui d'un curried function
qui utilise arrow function
et qui a un implicit return
pour le premier argument.
La fonction flèche lie lexicalement cette i.e, ils n'ont pas leur propre argument this
mais prennent la valeur this
de la portée englobante
Un équivalent du code ci-dessus serait
const handleChange = (field) {
return function(e) {
e.preventDefault();
/// Do something here
}.bind(this);
}.bind(this);
Une autre chose à noter à propos de votre exemple est que définir handleChange
en tant que const ou une fonction. Vous l’utilisez probablement dans le cadre d’une méthode de classe et il utilise un class fields syntax
donc au lieu de lier directement la fonction externe, vous le lieriez dans le constructeur de la classe
class Something{
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(field) {
return function(e) {
e.preventDefault();
// do something
}
}
}
Une autre chose à noter dans l'exemple est la différence entre le retour implicite et explicite.
const abc = (field) => field * 2;
Ci-dessus est un exemple de retour implicite ie. il prend le champ value en argument et renvoie le résultat field*2
qui spécifie explicitement la fonction à renvoyer
Pour un retour explicite, vous indiquez explicitement à la méthode de renvoyer la valeur
const abc = () => { return field*2; }
Une autre chose à noter concernant les fonctions de flèche est qu’elles ne possèdent pas leur propre variable arguments
, mais qu’elles héritent également de la portée des parents.
Par exemple, si vous définissez simplement une fonction de flèche comme
const handleChange = () => {
console.log(arguments) // would give an error on running since arguments in undefined
}
Comme alternative, les fonctions de flèche fournissent les paramètres de repos que vous pouvez utiliser
const handleChange = (...args) => {
console.log(args);
}
var handleChange = field => e => {
e.preventDefault();
/// Do something here
}
Dans Ecma5, le traducteur:
"use strict";
var handleChange = function handleChange(field) {
return function (e) {
e.preventDefault(); /// Do something here
};
};
var f = function(x,y) { return x+y }
var g = function(x) { return function(y) { return x+y }}
f: (T x T) -> T
g: T -> T -> T
T: type générique
Cela changera le type de la fonction, mais le résultat no.