Javascript javascript中的多个箭头函数是什么意思?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32782922/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What do multiple arrow functions mean in javascript?
提问by jhamm
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
}
回答by Thank you
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 same1code 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. The boldedtext is the return value of our function add
所以我们的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 …
因此,为了使用我们的柯里化函数,我们必须以不同的方式调用它……
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 actuallylook more like this …
然而,因为箭头函数在词法上是绑定的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
. 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. By using the handleChange
function, we can eliminate all the duplicated code that would result in setting up change
listeners for each field. Cool!
也许现在我们可以更清楚地看到这是做什么的。该handleChange
函数正在为指定的field
. 这是一种方便的 React 技术,因为您需要在每个输入上设置自己的侦听器以更新应用程序状态。通过使用该handleChange
函数,我们可以消除所有会导致change
为每个字段设置侦听器的重复代码。凉爽的!
1Here 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-
柯里化函数能够产生令人惊讶的事情。下面我们看到$
定义为带有两个参数的柯里化函数,但在调用点,看起来我们可以提供任意数量的参数。Currying 是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 -
部分应用是一个相关的概念。它允许我们部分应用函数,类似于柯里化,除了函数不必以柯里化形式定义 -
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">
回答by sdgluck
Understanding the available syntaxes of arrow functionswill 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 implicitlyreturned. 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 expressionhas a shorter syntax compared to function expressionsand lexically binds the thisvalue. Arrow functions are always anonymous.
This is particularly pertinent in your example considering that it is taken from a reactjsapplication. As as pointed out by @naomik, in React you often access a component's member functionsusing this
. For example:
考虑到它取自reactjs应用程序,这在您的示例中特别相关。作为由@naomik指出的那样,在你做出反应经常访问组件的成员函数使用this
。例如:
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) | }
回答by Rahil Ahmad
A general tip , if you get confused by any of new JS syntax and how it will compile , you can check babel. For example copying your code in babel and selecting the es2015 preset will give an output like this
一般提示,如果您对任何新的 JS 语法及其编译方式感到困惑,您可以查看babel。例如,在 babel 中复制您的代码并选择 es2015 预设将给出这样的输出
handleChange = function handleChange(field) {
return function (e) {
e.preventDefault();
// Do something here
};
};
回答by LifeQuery
Think of it like this, every time you see a arrow, you replace it with function
.function parameters
are defined before the arrow.
So in your example:
可以这样想,每次看到箭头时,都将其替换为function
。function parameters
在箭头之前定义。
所以在你的例子中:
field => // function(field){}
e => { e.preventDefault(); } // function(e){e.preventDefault();}
and then together:
然后一起:
function (field) {
return function (e) {
e.preventDefault();
};
}
从文档:
// 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
回答by sultan
Brief and simple
简明扼要
It is a function which returns another function written in short way.
它是一个函数,它返回另一个以简短方式编写的函数。
const handleChange = field => e => {
e.preventDefault()
// Do something here
}
// is equal to
function handleChange(field) {
return function(e) {
e.preventDefault()
// Do something here
}
}
Why people do it?
人们为什么这样做?
Have you faced when you need to write a function which can be customized? Or you have to write a callback function which has fixed parameters (arguments), but you need to pass more variables to the function but avoiding global variables? If your answer "yes" then it is the way how to do it.
您是否遇到过需要编写可自定义的函数的情况?或者您必须编写一个具有固定参数(参数)的回调函数,但您需要将更多变量传递给函数但避免全局变量?如果您的回答是“是”,那么这就是如何做到这一点。
For example we have a button
with onClick callback. And we need to pass id
to the function, but onClick
accepts only one parameter event
, we can not pass extra parameters within like this:
例如,我们有一个button
onClick 回调。我们需要传递id
给函数,但onClick
只接受一个参数event
,我们不能像这样传递额外的参数:
const handleClick = (event, id) {
event.preventDefault()
// Dispatch some delete action by passing record id
}
It will not work!
不起作用!
Therefore we make a function which will return other function with its own scope of variables without any global variables, because global variables are evil .
因此,我们创建了一个函数,该函数将返回具有自己变量范围的其他函数,而没有任何全局变量,因为全局变量是邪恶的。
Below the function handleClick(props.id)}
will be called and return a function and it will have id
in its scope! No matter how many times it will be pressed the ids will not effect or change each other, they are totally isolated.
下面的函数handleClick(props.id)}
将被调用并返回一个函数,它将id
在其范围内!无论按下多少次,id 都不会相互影响或改变,它们是完全隔离的。
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
)
回答by Shubham Khatri
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.
您问题中的示例是 a curried function
,它使用第一个参数arrow function
并具有 an implicit return
。
Arrow function lexically bind this i.e they do not have their own this
argument but take the this
value from the enclosing scope
箭头函数在词法上绑定 this 即它们没有自己的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. Probably you are using it as part of a class method and it uses a class fields syntax
关于您的示例还要注意的另一件事是定义handleChange
为常量或函数。可能您将它用作类方法的一部分,并且它使用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
上面是一个隐式返回的例子,即。它将 value 字段作为参数并返回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
但也从父作用域继承它。
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);
}
回答by Don Kartacs
It might be not totally related, but since the question mentioned react uses case (and I keep bumping into this SO thread): There is one important aspect of the double arrow function which is not explicitly mentioned here. Only the 'first' arrow(function) gets named (and thus 'distinguishable' by the run-time), any following arrows are anonymous and from React point of view count as a 'new' object on every render.
它可能不完全相关,但由于提到的问题反应用例(我一直在碰到这个 SO 线程):双箭头函数的一个重要方面在这里没有明确提到。只有“第一个”箭头(函数)被命名(因此在运行时“可区分”),任何后面的箭头都是匿名的,从 React 的角度来看,每次渲染时都被视为“新”对象。
Thus double arrow function will cause any PureComponent to rerender all the time.
因此双箭头函数将导致任何 PureComponent 一直重新渲染。
Example
例子
You have a parent component with a change handler as:
您有一个带有更改处理程序的父组件:
handleChange = task => event => { ... operations which uses both task and event... };
and with a render like:
并带有如下渲染:
{
tasks.map(task => <MyTask handleChange={this.handleChange(task)}/>
}
{
tasks.map(task => <MyTask handleChange={this.handleChange(task)}/>
}
handleChange then used on an input or click. And this all works and looks very nice. BUT it means that any change that will cause the parent to rerender (like a completely unrelated state change) will also re-render ALL of your MyTask as well even though they are PureComponents.
handleChange 然后用于输入或单击。这一切都有效并且看起来非常好。但这意味着任何会导致父级重新呈现的更改(如完全不相关的状态更改)也会重新呈现您的所有 MyTask,即使它们是 PureComponents。
This can be alleviated many ways such as passing the 'outmost' arrow and the object you would feed it with or writing a custom shouldUpdate function or going back to basics such as writing named functions (and binding the this manually...)
这可以通过多种方式缓解,例如传递“最外端”箭头和您将为其提供的对象或编写自定义 shouldUpdate 函数或返回基础知识,例如编写命名函数(并手动绑定 this...)