jha*_*amm 401 javascript ecmascript-6 arrow-functions
我一直在阅读一堆react代码,我看到这样的东西,我不明白:
handleChange = field => e => {
e.preventDefault();
/// Do something here
}
Run Code Online (Sandbox Code Playgroud)
Tha*_*you 700
这是一个咖喱的功能
首先,用两个参数检查这个函数......
const add = (x, y) => x + y
add(2, 3) //=> 5
Run Code Online (Sandbox Code Playgroud)
这里再次以咖喱形式......
const add = x => y => x + y
Run Code Online (Sandbox Code Playgroud)
这是没有箭头功能的相同1代码...
const add = function (x) {
return function (y) {
return x + y
}
}
Run Code Online (Sandbox Code Playgroud)
专注于 return
以另一种方式可视化它可能会有所帮助.我们知道箭头函数的工作方式是这样的 - 让我们特别注意返回值.
const f = someParam => returnValueRun Code Online (Sandbox Code Playgroud)
所以我们的add函数返回一个函数 - 我们可以使用括号来增加清晰度.该粗体文字是我们的函数的返回值add
const add = x => (y => x + y)Run Code Online (Sandbox Code Playgroud)
换句话说add,某些数字会返回一个函数
add(2) // returns (y => 2 + y)
Run Code Online (Sandbox Code Playgroud)
调用curried函数
所以为了使用我们的curried函数,我们不得不称之为有点不同......
add(2)(3) // returns 5
Run Code Online (Sandbox Code Playgroud)
这是因为第一个(外部)函数调用返回第二个(内部)函数.只有在我们调用第二个函数之后才能实际获得结果.如果我们将呼叫分成两行,这就更明显了......
const add2 = add(2) // returns function(y) { return 2 + y }
add2(3) // returns 5
Run Code Online (Sandbox Code Playgroud)
将我们的新理解应用于您的代码
好了,现在我们了解它是如何工作的,让我们来看看你的代码
handleChange = field => e => {
e.preventDefault()
/// Do something here
}
Run Code Online (Sandbox Code Playgroud)
我们将从不使用箭头功能代表它开始......
handleChange = function(field) {
return function(e) {
e.preventDefault()
// Do something here
// return ...
};
};
Run Code Online (Sandbox Code Playgroud)
但是,因为箭头函数在词法上绑定this,它实际上看起来更像是......
handleChange = function(field) {
return function(e) {
e.preventDefault()
// Do something here
// return ...
}.bind(this)
}.bind(this)
Run Code Online (Sandbox Code Playgroud)
也许现在我们可以更清楚地看到这一点.该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
Run Code Online (Sandbox Code Playgroud)
Curried函数能够令人惊讶.下面我们看到$定义为带有两个参数的curried函数,但在调用站点,看起来好像我们可以提供任意数量的参数.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) // 256Run Code Online (Sandbox Code Playgroud)
部分申请
部分应用是一个相关的概念.它允许我们部分应用函数,类似于currying,除了函数不必以curry形式定义 -
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
Run Code Online (Sandbox Code Playgroud)
这是一个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))Run Code Online (Sandbox Code Playgroud)
<input name="foo" placeholder="type here to see ascii codes" size="50">Run Code Online (Sandbox Code Playgroud)
sdg*_*uck 53
理解箭头函数的可用语法将使您了解它们在您提供的示例中"链接"时所引入的行为.
如果在没有块括号的情况下编写箭头函数(包含或不包含多个参数),则会隐式返回构成函数体的表达式.在您的示例中,该表达式是另一个箭头函数.
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()
} | | }
} | } | }
Run Code Online (Sandbox Code Playgroud)
使用箭头语法编写匿名函数的另一个优点是它们在词汇上与它们定义的范围绑定.来自MDN上的'箭头功能':
考虑到它来自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) | }
Run Code Online (Sandbox Code Playgroud)
Rah*_*mad 49
一般提示,如果您对任何新的JS语法以及如何编译它感到困惑,您可以检查babel.例如,在babel中复制代码并选择es2015预设将得到这样的输出
handleChange = function handleChange(field) {
return function (e) {
e.preventDefault();
// Do something here
};
};
Run Code Online (Sandbox Code Playgroud)
Lif*_*ery 40
可以这样想,每当你看到一个箭头,你就用它替换它function.function parameters在箭头之前定义.
所以在你的例子中:
field => // function(field){}
e => { e.preventDefault(); } // function(e){e.preventDefault();}
Run Code Online (Sandbox Code Playgroud)
然后在一起:
function (field) {
return function (e) {
e.preventDefault();
};
}
Run Code Online (Sandbox Code Playgroud)
来自文档:
// 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
Run Code Online (Sandbox Code Playgroud)
sul*_*tan 20
简短而简单
它是一个函数,它返回另一个以简短方式编写的函数。
const handleChange = field => e => {
e.preventDefault()
// Do something here
}
// is equal to
function handleChange(field) {
return function(e) {
e.preventDefault()
// Do something here
}
}
Run Code Online (Sandbox Code Playgroud)
人们为什么这样做?
在需要编写可以自定义的功能时遇到了什么?或者您必须编写一个具有固定参数(参数)的回调函数,但是您需要向该函数传递更多变量,但要避免使用全局变量?如果您的回答为“ 是 ”,那么这就是方法。
例如,我们有一个buttonwith onClick回调。而且我们需要传递id给函数,但onClick只接受一个参数event,因此不能像这样传递额外的参数:
const handleClick = (event, id) {
event.preventDefault()
// Dispatch some delete action by passing record id
}
Run Code Online (Sandbox Code Playgroud)
不起作用!
因此,我们将创建一个函数,该函数将返回具有其自己的变量范围的其他函数,而没有任何全局变量,因为全局变量是邪恶的。
下面的函数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
)
Run Code Online (Sandbox Code Playgroud)
小智 5
它可能不完全相关,但由于提到的问题反应用例(我一直在碰到这个 SO 线程):双箭头函数的一个重要方面在这里没有明确提到。只有“第一个”箭头(函数)被命名(因此在运行时被“区分”),任何后面的箭头都是匿名的,从 React 的角度来看,每次渲染时都被视为“新”对象。
因此双箭头函数将导致任何 PureComponent 一直重新渲染。
例子
您有一个带有更改处理程序的父组件:
handleChange = task => event => { ... operations which uses both task and event... };
Run Code Online (Sandbox Code Playgroud)
并带有如下渲染:
{
tasks.map(task => <MyTask handleChange={this.handleChange(task)}/>
}
handleChange 然后用于输入或单击。这一切都有效并且看起来非常好。但这意味着任何会导致父级重新呈现的更改(如完全不相关的状态更改)也会重新呈现您的所有 MyTask,即使它们是 PureComponents。
这可以通过多种方式缓解,例如传递“最外层”箭头和您将为其提供的对象或编写自定义 shouldUpdate 函数或回到基础知识,例如编写命名函数(并手动绑定 this...)
| 归档时间: |
|
| 查看次数: |
65781 次 |
| 最近记录: |