多个箭头函数在 JavaScript 中是什么意思?

我一直在阅读一堆 React 代码,我看到这样我不明白的东西:

handleChange = field => e => {
  e.preventDefault();
  /// Do something here
}

答案 1

这是一个咖喱功能

首先,使用两个参数检查此函数...

const add = (x, y) => x + y
add(2, 3) //=> 5

在这里,它再次以咖喱形式...

const add = x => y => x + y

这是相同的1代码,没有箭头函数...

const add = function (x) {
  return function (y) {
    return x + y
  }
}

关注回报

从另一个角度来可视化它可能会有所帮助。我们知道箭头函数的工作方式是这样的 - 让我们特别注意返回值

const f = someParam => returnValue

所以我们的函数返回一个函数 - 我们可以使用括号来增加清晰度。粗体文本是我们函数的返回值addadd

const add = x => (y => x + y)

换句话说,某个数字返回一个函数add

add(2) // returns (y => 2 + y)

调用已启动的函数

因此,为了使用我们的curried函数,我们必须以不同的方式调用它......

add(2)(3)  // returns 5

这是因为第一个(外部)函数调用返回第二个(内部)函数。只有在调用第二个函数之后,我们才能真正得到结果。如果我们将呼叫分开两条线,这一点就更明显了......

const add2 = add(2) // returns function(y) { return 2 + y }
add2(3)             // returns 5

将我们的新理解应用于您的代码

相关:“装订,部分应用和咖喱有什么区别?

好了,现在我们了解了它是如何工作的,让我们来看看你的代码。

handleChange = field => e => {
  e.preventDefault()
  /// Do something here
}

我们将从不使用箭头函数来表示它开始...

handleChange = function(field) {
  return function(e) {
    e.preventDefault()
    // Do something here
    // return ...
  };
};

但是,由于箭头功能在词法上绑定,它实际上看起来更像这样......this

handleChange = function(field) {
  return function(e) {
    e.preventDefault()
    // Do something here
    // return ...
  }.bind(this)
}.bind(this)

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

1 在这里,我不必在词法上绑定,因为原始函数不使用任何上下文,因此在这种情况下保留它并不重要。thisadd


更多箭头

如有必要,可以对两个以上的箭头函数进行排序 -

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函数,但在调用站点,似乎我们可以提供任意数量的参数。咖喱是阿瑞提的抽象$ -

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

部分申请

部分应用是一个相关的概念。它允许我们部分应用函数,类似于咖喱,除了函数不必以咖喱形式定义 -

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

这是一个工作演示,您可以在自己的浏览器中玩 -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">

答案 2

简要

它是一个返回以简短方式编写的另一个函数的函数。

const handleChange = field => e => {
  e.preventDefault()
  // Do something here
}

// is equal to 
function handleChange(field) {
  return function(e) {
    e.preventDefault()
    // Do something here
  }
}

为什么?

您是否曾经遇到过需要创建可自定义功能的情况?或者,也许您有一个具有固定参数的回调函数,但是您需要在避免全局变量的同时发送额外的变量?如果你的回答是肯定的,那么这就是如何做到这一点的方法。

例如,我们有一个带有回调的按钮。我们想要传递给函数,但是,只接受一个参数,所以我们不能这样做:onClickidonClickevent

const handleClick = (event, id) {
  event.preventDefault()
  // Dispatch some delete action by passing record 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
)

功能组成

多个箭头函数也称为“咖喱函数”,它们用于函数组合。

// It is just an example, unfortunately, redux does not export dispatch function
import {dispatch, compose} from 'redux'

const pickSelectedUser = props => {
  const {selectedName, users} = props
  const foundUser = users.find(user => user.name === selectedName)
  
  return foundUser.id
}

const deleteUser = userId => event => {
  event.preventDefault()
  dispatch({
    type: `DELETE_USER`,
    userId,
  })
}

// The compose function creates a new function that accepts a parameter.
// The parameter will be passed throw the functions from down to top.
// Each function will change the value and pass it to the next function
// By changing value it was not meant a mutation
const handleClick = compose(
  deleteUser,
  pickSelectedUser,
)

const Confirm = props => (
  <div>
    <h1>Are you sure to delete?</h1>
    <button onClick={handleClick(props)}>
      Delete
    </button>
  </div
)