此文章是本人在学习React的时候,写下的学习笔记,在此纪录和分享。此为第九篇,主要介绍高阶函数与函数柯里化。
高阶函数,和函数的柯里化,是学习react的拓展,方便以后优化代码,更好的学习react。
目录
高阶函数
案例
高阶函数定义
函数的柯里化
函数柯里化的定义
柯里化小案例
不用柯里化的写法
高阶函数
案例
先把上一笔记里面的案例,拿出来:这个案例就是,两个输入框分别是用户名和密码,输入用户名和密码,点击登录按钮,会弹出一个提示框,显示你输入的用户名和密码。
<!-- 准备好容器 -->
<div id="test1"></div>
<script src="https://cdn.staticfile.org/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.staticfile.org/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
<!-- 新引入的库,用于限定props传入值的类型,propTypes -->
<script src="https://cdn.bootcss.com/prop-types/15.6.1/prop-types.js"></script>
<script type="text/babel">
class Login extends React.Component {
//状态初始化
state = {
username:'',//用户名
password:''//密码
}
//保存用户名到状态中
saveUsername = (event)=>{
this.setState({username:event.target.value})
}
//保存密码到状态中
savePassword = (event)=>{
this.setState({password:event.target.value})
}
//表单提交的回调
handleSubmit = (event) => {
event.preventDefault()
const {username,password} = this.state
alert(`您输入的用户名是${username},输入的密码是${password}`)
}
render() {
return (
<form action="http://www.atguigu.com" onSubmit={this.handleSubmit}>
用户名:<input onChange = {this.saveUsername} type="text" name="username" />
密码:<input onChange = {this.savePassword} type="password" name="password" />
<button>登录</button>
</form>
)
}
}
ReactDOM.render(<Login />, document.getElementById('test1'))
</script>
如代码所示,表单中需要获取用户名和密码,并且加以操作,所以有了对应的两个方法:saveUsername和savePassword。但如果还存在性别,年龄,电话号码等等信息需要操作,是不是得一一对应,写很多方法?实在是过于冗余,有没有什么解决的办法?
所以我们只写一个方法saveFormData来代替saveUsername和savePassword,来给表单中所有的属性使用:
用户名:<input onChange = {this.saveFormData("username")} type="text" name="username" />
密码:<input onChange = {this.saveFormData("password")} type="password" name="password" />
saveFormData = (event)=>{
this.setState({
password:event.target.value
})
}
但是,这会出现很大的错误。注意onchange的回调函数,它非是一个函数进行了回调,而是一个函数的返回结果进行了回调:this.saveFormData("username"),saveFormData加了小括号,已经在回调时执行完了,产生了函数的返回值,这个返回值参与了回调,就会发生错误。
必须将一个函数返回给onchange作为回调。
如下的写法,才是onchange事件触发时候,回调saveFormData这个函数。
<input onChange = {this.saveFormData}
而且这个saveFromData函数,this.setState也会一直把数据给password。我们接下来修改这些错误。
那么怎么才能在加()的情况下,也能正确执行回调函数呢。众所周知函数加了()就是执行函数产生返回值,那么我们直接让返回值是一个函数不就行了。
改写这个saveFromData函数:
//保存表单数据到状态中
saveFormData = (dataType) => {
return (event) => {
this.setState({
[dataType]: event.target.value
})
}
}
我们将saveFromData函数的返回值,写成了一个函数。如此一来,onchange事件触发后,回调saveFromData函数的返回值,仍然是一个函数,便能达到正常的效果。
我们在onChange={this.saveFormData("username")}中传入参数,在saveFromData函数设置形参dataType接收这个参数,在this.setState中以中括号包裹形参(中括号表示其中是是一个变量,不写中括号会当作一个键名),设置state,这样就可以区分数据,在state中分开保存不同的数据。
来看效果:
高阶函数定义
高阶函数:如果一个函数符合下面两个规范中的任何一个,那该函数就是高阶函数。
1.若A函数,接收的参数是一个函数,那么A就可以被称为高阶函数。
2.若A函数,调用的返回值依然是一个函数,那么A就可以被称为高阶函数。
由此可见:saveFromData函数就是一个高阶函数,调用的返回值是一个函数。
常见的高阶函数,如promise,数组迭代的那几种方法,定时器。
函数的柯里化
函数柯里化的定义
函数的柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式。
柯里化小案例
为了理解柯里化,我们先正常的写一个普通函数的案例:a,b,c 的求和
function sum(a,b,c){
return a+b+c
}
const result = sum(1,2,3)
console.log(result);
现在把上面的案例,改成柯里化的写法:
function sum(a) {
return (b) => {
return (c) => {
return a + b + c
}
}
}
const result = sum(1)(2)(3)
console.log(result);
这个案例里面的函数柯里化,看似把简单的问题复杂化,变得麻烦,又有些回调地狱的风格。但实际应用上,函数柯里化经常使用。比如说第一个案例,里面的saveFromData函数:
saveFormData = (dataType) => {
return (event) => {
this.setState({
[dataType]: event.target.value
})
}
}
先接收了参数dataType,然后再接收了event参数,在后面对两个参数统一处理了,这就是函数的柯里化。
不用柯里化的写法
如果我们不用柯里化的写法,这就要求我们一次性拿到所有参数。主要是在onchange事件里,想办法把两个参数一次性给saveFromData函数传过去。
给onchange事件回调的,必须是一个函数。我们尝试写一个内联函数,这样既能在内联函数中把参数传递给saveFromData函数,又可以保证是一个函数回调给事件。
如下:onChange={(event)=>{this.saveFormData('username',event.target.value)}}
用户名:<input onChange={(event)=>{this.saveFormData('username',event)}} type="text" name="username" />
密码:<input onChange={(event)=>{this.saveFormData('password',event)}} type="password" name="password" />
然后我们就可以把saveFromData函数改写成一个普通的函数:
saveFormData = (dataType, event) => {
this.setState({
[dataType]: event.target.value
})
}
如此,我们改写了这两个部分,就可以把柯里化写法,改成普通的函数写法。