JavaScript中的多箭头函数指什么?
JavaScript中的多箭头函数指什么?
我一直在阅读一堆React代码,我看到像这样的东西,我不理解:
handleChange = field => e => { e.preventDefault(); /// Do something here }
简述
这是一种以简短的方式编写返回另一个函数的函数。
const handleChange = field => e => { e.preventDefault() // Do something here } // is equal to function handleChange(field) { return function(e) { e.preventDefault() // Do something here } }
动机
在某些情况下,我们需要传递额外的变量给一个带有固定参数的回调函数,但不希望使用全局变量。
例如,我们有一个按钮有一个onClick
回调函数,我们想要传递一个变量,比如id
,但onClick
只接受一个参数event
,这就使得我们无法同时传递id
和event
。
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 => (Are you sure to delete?
函数组合
多个箭头函数也被称为“柯里化函数”,用于函数组合。
import {compose} from 'redux' import {store} from './store.js' const pickSelectedUser = props => { const {selectedName, users} = props const foundUser = users.find(user => user.name === selectedName) return foundUser.id } const deleteUser = userId => event => { event.preventDefault() store.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 => (Are you sure to delete?
这是一个< a href="https://en.wikipedia.org/wiki/Currying" rel="noreferrer">柯里化函数
首先,让我们看一下这个具有两个参数的函数...
const add = (x, y) => x + y add(2, 3) //=> 5
这是一个柯里化形式的函数...
const add = x => y => x + y
这里是同样的代码,但没有箭头函数...
const add = function (x) { return function (y) { return x + y } }
关注return
另外一种方式来观察这个问题可能会有所帮助。 我们知道箭头函数是如何工作的-让我们特别关注返回值。
const f = someParam => returnValue
因此,我们的add
函数返回一个函数-我们可以使用括号来增加清晰度。 粗体文本是我们函数add
的返回值。
const add = x => (y => x + y)
换句话说,add
与某个数字一起返回一个函数。
add(2) // returns (y => 2 + y)
调用柯里化函数
为了使用我们的柯里化函数,我们必须稍微不同地调用它...
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)
也许现在我们可以更清楚地看到这是在做什么。 handleChange
函数为指定的 field
创建一个函数。这是一个便捷的 React 技巧,因为您需要在每个输入上设置自己的监听器以更新应用程序的状态。通过使用 handleChange
函数,我们可以消除所有会导致为每个字段设置 change
监听器的重复代码。酷!
1 这里我不必词法绑定 this
,因为原始的 add
函数没有使用任何上下文,所以在这种情况下保留它不重要。
甚至更多箭头
如果有必要,可以依次排列多个箭头函数——
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
柯里化函数能够做出令人惊讶的事情。下面我们看到将 $
定义为具有两个参数的柯里化函数,但在调用站点上,似乎我们可以提供任意数量的参数。柯里化是 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
偏函数应用
部分应用是一个相关的概念。它允许我们部分地应用函数,类似于柯里化,但函数不必定义为柯里化形式——
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))