What do multiple arrow functions mean in javascript?
我一直在阅读一堆
1 2 3 4 | handleChange = field => e => { e.preventDefault(); /// Do something here } |
这是一个咖喱的功能
首先,使用两个参数检查此函数
1 2 | const add = (x, y) => x + y add(2, 3) //=> 5 |
在这里,它再次以咖喱形式出现
1 | const add = x => y => x + y |
这是没有箭头功能的相同1代码
1 2 3 4 5 | const add = function (x) { return function (y) { return x + y } } |
专注于
以另一种方式可视化它可能会有所帮助。我们知道箭头函数的工作方式是这样的 - 让我们特别注意返回值。
1 | const f = someParam => returnValue |
所以我们的
1 | const add = x => (y => x + y) |
换句话说,某些数字的
1 | add(2) // returns (y => 2 + y) |
调用curried函数
因此,为了使用我们的curried函数,我们必须稍微改变它
1 | add(2)(3) // returns 5 |
这是因为第一个(外部)函数调用返回第二个(内部)函数。只有在我们调用第二个函数之后才能实际获得结果。如果我们将呼叫分成两行,这一点就更明显了
1 2 | const add2 = add(2) // returns function(y) { return 2 + y } add2(3) // returns 5 |
将我们的新理解应用于您的代码
related:"What’s the difference between binding, partial application, and currying?"
好了,现在我们了解它是如何工作的,让我们来看看你的代码
1 2 3 4 | handleChange = field => e => { e.preventDefault() /// Do something here } |
我们首先在不使用箭头功能的情况下进行表示
1 2 3 4 5 6 7 | handleChange = function(field) { return function(e) { e.preventDefault() // Do something here // return ... }; }; |
但是,因为箭头函数在词法上绑定
1 2 3 4 5 6 7 | handleChange = function(field) { return function(e) { e.preventDefault() // Do something here // return ... }.bind(this) }.bind(this) |
也许现在我们可以更清楚地看到这一点。
1这里我没有词法绑定
更多的箭头
如有必要,可以对两个以上的箭头功能进行排序 -
1 2 3 4 5 6 7 8 9 | 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函数能够令人惊讶。下面我们看到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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 |
部分申请
部分应用是一个相关的概念。它允许我们部分应用函数,类似于currying,除了函数不必以curry形式定义 -
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 |
这是你可以在自己的浏览器中玩的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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)) |
1 | <input name="foo" placeholder="type here to see ascii codes" size="50"> |
理解箭头函数的可用语法将使您了解它们在您提供的示例中"链接"时所引入的行为。
如果在没有块括号的情况下编写箭头函数(包含或不包含多个参数),则会隐式返回构成函数体的表达式。在您的示例中,该表达式是另一个箭头函数。
1 2 3 4 5 6 7 | 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() } | | } } | } | } |
使用箭头语法编写匿名函数的另一个优点是它们在词法上与它们的定义范围绑定。来自MDN上的'箭头功能':
An arrow function expression has a shorter syntax compared to function expressions and lexically binds the this value. Arrow functions are always anonymous.
考虑到它来自reactjs应用程序,这在您的示例中尤为重要。正如@naomik所指出的,在React中,您经常使用
1 2 3 4 5 6 7 | 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) | } |
一般提示,如果您对任何新的JS语法以及如何编译它感到困惑,您可以检查babel。例如,在babel中复制代码并选择es2015预设将得到这样的输出
1 2 3 4 5 6 | handleChange = function handleChange(field) { return function (e) { e.preventDefault(); // Do something here }; }; |
想象一下,每次看到箭头时,都要用
所以在你的例子中:
1 2 | field => // function(field){} e => { e.preventDefault(); } // function(e){e.preventDefault();} |
然后在一起:
1 2 3 4 5 | function (field) { return function (e) { e.preventDefault(); }; } |
来自文档:
1 2 3 4 5 6 7 8 | // 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 |
简单而简单?
它是一个返回另一个简短写入函数的函数。
1 2 3 4 5 6 7 8 9 10 11 12 | const handleChange = field => e => { e.preventDefault() // Do something here } // is equal to function handleChange(field) { return function(e) { e.preventDefault() // Do something here } } |
为什么人们这样做?
您是否需要编写可自定义的功能?
或者你必须编写一个具有固定参数(参数)的回调函数,
但是你需要将更多变量传递给函数但是要避免全局变量吗?
如果你的答案是肯定的,那就是如何做到的。
例如,我们有一个带有onClick回调的
1 2 3 4 | const handleClick = (event, id) { event.preventDefault() // Dispatch some delete action by passing record id } |
不起作用!
因此,我们创建一个函数,它将返回具有自己的变量范围的其他函数,而不需要任何全局变量,因为全局变量是邪恶的。
函数
1 2 3 4 5 6 7 8 9 10 11 12 13 | const handleClick = id => event { event.preventDefault() // Dispatch some delete action by passing record id } const Confirm = props => ( Are you sure to delete? <button onClick={handleClick(props.id)}> Delete </button> </div ) |
您的问题中的示例是
箭头函数通过词法绑定它,即它们没有自己的
相当于上面的代码
1 2 3 4 5 6 | const handleChange = (field) { return function(e) { e.preventDefault(); /// Do something here }.bind(this); }.bind(this); |
关于您的示例还有一点需要注意的是将
所以不是直接绑定外部函数,而是将它绑定在类构造函数中
1 2 3 4 5 6 7 8 9 10 11 12 | class Something{ constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); } handleChange(field) { return function(e) { e.preventDefault(); // do something } } } |
在示例中要注意的另一件事是隐式和显式返回之间的区别。
1 | const abc = (field) => field * 2; |
以上是隐式回报的一个例子,即。它将value字段作为参数并返回结果
对于显式返回,您将明确告诉方法返回值
1 | const abc = () => { return field*2; } |
关于箭头函数的另一个注意事项是它们没有自己的
例如,如果你只是定义一个箭头函数
1 2 3 | const handleChange = () => { console.log(arguments) // would give an error on running since arguments in undefined } |
作为替代箭头,函数提供了您可以使用的其余参数
1 2 3 | const handleChange = (...args) => { console.log(args); } |
1 2 3 4 | var handleChange = field => e => { e.preventDefault(); /// Do something here } |
在Ecma5中,翻译:
1 2 3 4 5 6 7 8 9 10 11 12 13 | "use strict"; var handleChange = function handleChange(field) { return function (e) { e.preventDefault(); /// Do something here }; }; var f = function(x,y) { return x+y } var g = function(x) { return function(y) { return x+y }} f: (T x T) -> T g: T -> T -> T |
T:泛型
它会改变函数的类型,但结果没有。