本文翻译自:What do multiple arrow functions mean in javascript?
I have been reading a bunch of react
code and I see stuff like this that I don't understand: 我一直在读一堆react
代码,我看到一些我不明白的东西:
handleChange = field => e => {
e.preventDefault();
/// Do something here
}
#1楼
参考:https://stackoom.com/question/2DYKo/javascript中的多个箭头功能是什么意思
#2楼
Think of it like this, every time you see a arrow, you replace it with function
. 这样想吧,每次看到箭头时,都将其替换为function
。 function parameters
are defined before the arrow. function parameters
在箭头之前定义。
So in your example: 因此,在您的示例中:
field => // function(field){}
e => { e.preventDefault(); } // function(e){e.preventDefault();}
and then together: 然后一起:
function (field) {
return function (e) {
e.preventDefault();
};
}
From the docs : 从文档 :
// 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
#3楼
Understanding the available syntaxes of arrow functions will give you an understanding of what behaviour they are introducing when 'chained' like in the examples you provided. 了解箭头函数的可用语法将使您了解“链接”时它们所引入的行为,如您提供的示例中所示。
When an arrow function is written without block braces, with or without multiple parameters, the expression that constitutes the function's body is implicitly returned. 当编写不带大括号,带有或不带有多个参数的箭头函数时,将隐式返回构成函数主体的表达式。 In your example, that expression is another arrow function. 在您的示例中,该表达式是另一个箭头函数。
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()
} | | }
} | } | }
Another advantage of writing anonymous functions using the arrow syntax is that they are bound lexically to the scope in which they are defined. 使用箭头语法编写匿名函数的另一个优点是将它们按词法绑定到定义它们的范围。 From 'Arrow functions' on MDN : 从MDN上的“箭头功能” :
An arrow function expression has a shorter syntax compared to function expressions and lexically binds the this value. 箭头函数表达式的语法比函数表达式短,并且在词法上绑定了此值。 Arrow functions are always anonymous . 箭头函数始终是匿名的 。
This is particularly pertinent in your example considering that it is taken from a reactjs application. 考虑到它是从reactjs应用程序中获取的,这在您的示例中特别相关。 As as pointed out by @naomik, in React you often access a component's member functions using this
. 正如@naomik指出的那样,在React中,您经常使用this
访问组件的成员函数 。 For example: 例如:
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) | }
#4楼
That is a curried function 那是一个咖喱函数
First, examine this function with two parameters … 首先,使用两个参数检查此功能……
const add = (x, y) => x + y
add(2, 3) //=> 5
Here it is again in curried form … 这里又是咖喱形式的……
const add = x => y => x + y
Here is the same 1 code without arrow functions … 这是没有箭头功能的相同1个代码……
const add = function (x) {
return function (y) {
return x + y
}
}
Focus on return
专注于return
It might help to visualize it another way. 用另一种方式可视化可能会有所帮助。 We know that arrow functions work like this – let's pay particular attention to the return value . 我们知道箭头函数是这样工作的-让我们特别注意返回值 。
const f = someParam => returnValue
So our add
function returns a function – we can use parentheses for added clarity. 因此,我们的add
函数返回一个函数 –我们可以使用括号来增加清晰度。 The bolded text is the return value of our function add
粗体字是我们函数add
的返回值
const add = x => (y => x + y)
In other words add
of some number returns a function 换句话说,一些数字的add
返回一个函数
add(2) // returns (y => 2 + y)
Calling curried functions 调用咖喱函数
So in order to use our curried function, we have to call it a bit differently … 因此,为了使用我们的curried函数,我们必须对其进行一些不同的调用……
add(2)(3) // returns 5
This is because the first (outer) function call returns a second (inner) function. 这是因为第一个(外部)函数调用返回了第二个(内部)函数。 Only after we call the second function do we actually get the result. 只有在调用第二个函数之后,我们才真正得到结果。 This is more evident if we separate the calls on two lines … 如果我们将呼叫分隔在两行上,则更明显……
const add2 = add(2) // returns function(y) { return 2 + y }
add2(3) // returns 5
Applying our new understanding to your code 将我们的新知识应用于您的代码
related: ”What's the difference between binding, partial application, and currying?” 相关: “绑定,部分应用和柯林有什么区别?”
OK, now that we understand how that works, let's look at your code 好,现在我们了解了它的工作原理,让我们看一下您的代码
handleChange = field => e => {
e.preventDefault()
/// Do something here
}
We'll start by representing it without using arrow functions … 我们将从不使用箭头功能来表示它开始……
handleChange = function(field) {
return function(e) {
e.preventDefault()
// Do something here
// return ...
};
};
However, because arrow functions lexically bind this
, it would actually look more like this … 但是,由于arrow函数用词法绑定了this
,因此实际上看起来更像这样……
handleChange = function(field) {
return function(e) {
e.preventDefault()
// Do something here
// return ...
}.bind(this)
}.bind(this)
Maybe now we can see what this is doing more clearly. 也许现在我们可以更清楚地看到它在做什么。 The handleChange
function is creating a function for a specified field
. handleChange
函数正在为指定field
创建一个函数。 This is a handy React technique because you're required to setup your own listeners on each input in order to update your applications state. 这是一种方便的React技术,因为您需要在每个输入上设置自己的侦听器以更新您的应用程序状态。 By using the handleChange
function, we can eliminate all the duplicated code that would result in setting up change
listeners for each field. 通过使用handleChange
函数,我们可以消除所有重复的代码,这些代码将导致为每个字段设置change
侦听器。 Cool! 凉!
1 Here I did not have to lexically bind this
because the original add
function does not use any context, so it is not important to preserve it in this case. 1在这里,我不必用词法绑定this
因为原始的add
函数不使用任何上下文,因此在这种情况下保留它并不重要。
Even more arrows 甚至更多的箭
More than two arrow functions can be sequenced, if necessary - 如有必要,可以排序两个以上的箭头功能-
const three = a => b => c =>
a + b + c
const four = a => b => c => d =>
a + b + c + d
three (1) (2) (3) // 6
four (1) (2) (3) (4) // 10
Curried functions are capable of surprising things. 咖喱函数能够使人惊讶。 Below we see $
defined as a curried function with two parameters, yet at the call site, it appears as though we can supply any number of arguments. 在下面,我们看到$
被定义为具有两个参数的咖喱函数,但是在调用站点,似乎我们可以提供任意数量的参数。 Currying is the abstraction of arity - 柯里是抽象元数 -
const $ = x => k => $ (k (x)) const add = x => y => x + y const mult = x => y => x * y $ (1) // 1 (add (2)) // + 2 = 3 (mult (6)) // * 6 = 18 (console.log) // 18 $ (7) // 7 (add (1)) // + 1 = 8 (mult (8)) // * 8 = 64 (mult (2)) // * 2 = 128 (mult (2)) // * 2 = 256 (console.log) // 256
Partial application 部分申请
Partial application is a related concept. 部分应用是一个相关的概念。 It allows us to partially apply functions, similar to currying, except the function does not have to be defined in curried form - 它允许我们部分地应用函数,类似于currying,除了不必以咖喱形式定义函数-
const partial = (f, ...a) => (...b) =>
f (...a, ...b)
const add3 = (x, y, z) =>
x + y + z
partial (add3) (1, 2, 3) // 6
partial (add3, 1) (2, 3) // 6
partial (add3, 1, 2) (3) // 6
partial (add3, 1, 2, 3) () // 6
partial (add3, 1, 1, 1, 1) (1, 1, 1, 1, 1) // 3
Here's a working demo of partial
you can play with in your own browser - 这是您可以在自己的浏览器中播放的partial
工作演示-
const partial = (f, ...a) => (...b) => f (...a, ...b) const preventDefault = (f, event) => ( event .preventDefault () , f (event) ) const logKeypress = event => console .log (event.which) document .querySelector ('input[name=foo]') .addEventListener ('keydown', partial (preventDefault, logKeypress))
<input name="foo" placeholder="type here to see ascii codes" size="50">
#5楼
A general tip , if you get confused by any of new JS syntax and how it will compile , you can check babel . 一般提示,如果您对任何新的JS语法及其编译方式感到困惑,则可以检查babel 。 For example copying your code in babel and selecting the es2015 preset will give an output like this 例如,将您的代码复制到babel中并选择es2015预设将给出这样的输出
handleChange = function handleChange(field) {
return function (e) {
e.preventDefault();
// Do something here
};
};
#6楼
The example in your question is that of a curried function
which makes use of arrow function
and has an implicit return
for the first argument. 您问题中的示例是使用arrow function
的curried function
示例,并且第一个参数具有implicit return
。
Arrow function lexically bind this ie they do not have their own this
argument but take the this
value from the enclosing scope 箭头函数用词法绑定此对象,即它们没有自己的this
参数,但从封闭范围获取this
值
An equivalent of the above code would be 与上面的代码等效
const handleChange = (field) {
return function(e) {
e.preventDefault();
/// Do something here
}.bind(this);
}.bind(this);
One more thing to note about your example is that define handleChange
as a const or a function. 关于您的示例要注意的另一件事是将handleChange
定义为const或函数。 Probably you are using it as part of a class method and it uses a class fields syntax
可能您将其用作类方法的一部分,并且使用了class fields syntax
so instead of binding the outer function directly, you would bind it in the class constructor 因此,与其直接绑定外部函数,不如将其绑定到类构造函数中
class Something{
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(field) {
return function(e) {
e.preventDefault();
// do something
}
}
}
Another thing to note in the example is the difference between implicit and explicit return. 该示例中要注意的另一件事是隐式和显式返回之间的区别。
const abc = (field) => field * 2;
Above is an example of implicit return ie. 上面是隐式返回的示例,即。 it takes the value field as argument and returns the result field*2
which explicitly specifying the function to return 它以值字段作为参数并返回结果field*2
,该field*2
显式指定要返回的函数
For an explicit return you would explicitly tell the method to return the value 对于显式返回,您将显式告诉方法返回值
const abc = () => { return field*2; }
Another thing to note about arrow functions is that they do not have their own arguments
but inherit that from the parents scope as well. 关于箭头函数要注意的另一件事是它们没有自己的arguments
但也从父级范围继承了该arguments
。
For example if you just define an arrow function like 例如,如果您仅定义一个箭头函数,例如
const handleChange = () => {
console.log(arguments) // would give an error on running since arguments in undefined
}
As an alternative arrow functions provide the rest parameters that you can use 作为替代,箭头函数提供您可以使用的其余参数
const handleChange = (...args) => {
console.log(args);
}