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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 14:12:39  来源:igfitidea点击:

What do multiple arrow functions mean in javascript?

javascriptecmascript-6arrow-functions

提问by jhamm

I have been reading a bunch of reactcode 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 addfunction 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 addof 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 handleChangefunction 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 handleChangefunction, we can eliminate all the duplicated code that would result in setting up changelisteners for each field. Cool!

也许现在我们可以更清楚地看到这是做什么的。该handleChange函数正在为指定的field. 这是一种方便的 React 技术,因为您需要在每个输入上设置自己的侦听器以更新应用程序状态。通过使用该handleChange函数,我们可以消除所有会导致change为每个字段设置侦听器的重复代码。凉爽的!

1Here I did not have to lexically bind thisbecause the original addfunction 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 partialyou 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
   };
 };

babel

通天塔

回答by LifeQuery

Think of it like this, every time you see a arrow, you replace it with function.
function parametersare 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(); 
    };
}

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

回答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 buttonwith onClick callback. And we need to pass idto the function, but onClickaccepts only one parameter event, we can not pass extra parameters within like this:

例如,我们有一个buttononClick 回调。我们需要传递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 idin 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 functionwhich makes use of arrow functionand has an implicit returnfor the first argument.

您问题中的示例是 a curried function,它使用第一个参数arrow function并具有 an implicit return

Arrow function lexically bind this i.e they do not have their own thisargument but take the thisvalue 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 handleChangeas 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*2which 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 argumentsbut 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...)