函数柯里化

高阶函数 :如果一个函数的参数或返回值仍为函数,则该函数为高阶函数。如Promise()、setTimeout()、Array.prototype.map()等
函数的柯里化 :通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式

示例:假设一个求和函数sum如下所示

js 复制代码
function sum(a,b,c){
	return a+b+c
}
console.log(sum(1,2,3)); // 6

将其修改成以下形式就是函数的柯里化

js 复制代码
function sum(a){
	return function(b){
		return function(c){
			return a+b+c
		}
	}
}
console.log(sum(1)(2)(3)); // 6

函数柯里化让代码更复杂了,那一般什么场景用函数柯里化呢?

答:当参数不方便一次性都传递过去的时候可以考虑用函数柯里化

举例:假设要实现如下功能,点击登录会有弹出框,显示当前输入的用户名和密码。以下示例用了React框架去实现

不用柯里化的时候,要针对多个输入字段写它自己的onChange回调函数(saveUsername和savePassword),saveUsername和savePassword代码重复率很高,如果有多个输入字段的值需要实时记录到组件的state中,那就要写多个字段onChange对应的回调函数,但是这些回调函数的区别就是setState存储的字段不同。这样代码会导致代码冗余度比较高

js 复制代码
<body>
	<!-- 准备好一个"容器" -->
	<div id="test"></div>
	
	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.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 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('test'))
	</script>
</body>

有没有办法让这些输入性质的标签的onChange回调共用一个回调函数,这个回调函数接收该标签绑定的字段,这样就可以根据标签绑定的字段修改state中相应的字段值了。但是onChange接收一个回调函数并且这个回调函数只有一个参数event。该如何解决这个问题呢?如下有2种解决方式

方法一:使用柯里化

onChange,onSubmit等需要赋值给它一个函数,函数柯里化使得函数执行的返回值仍是函数,就可以实现这样的需求。saveFormData返回一个函数,这个函数是onChange的回调,所以这个回调函数第一个参数是event,因为外层函数已经传入了datatype,所以在这个函数里可以同时使用字段类型dataType和event参数。

js 复制代码
<body>
	<!-- 准备好一个"容器" -->
	<div id="test"></div>
	
	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		//创建组件
		class Login extends React.Component{
			//初始化状态
			state = {
				username:'', //用户名
				password:'' //密码
			}

			//保存表单数据到状态中
			// saveFormData返回一个函数,这个函数是onChange的回调,所以这个回调函数第一个参数是event,因为外层函数已经传入了datatype,所以在这个函数里可以同时使用字段类型dataType和event参数
			saveFormData = (dataType)=>{
				return (event)=>{
					// 注意不要写成{dataType:event.target.value},因为dataType是变量不是字符串的字段名
					this.setState({[dataType]:event.target.value})
				}
			}

			//表单提交的回调
			handleSubmit = (event)=>{
				event.preventDefault() //阻止表单提交
				const {username,password} = this.state
				alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
			}
			render(){
				return(
					<form onSubmit={this.handleSubmit}>
						用户名:<input onChange={this.saveFormData('username')} type="text" name="username"/>
						密码:<input onChange={this.saveFormData('password')} type="password" name="password"/>
						<button>登录</button>
					</form>
				)
			}
		}
		//渲染组件
		ReactDOM.render(<Login/>,document.getElementById('test'))
	</script>
</body>

方法二:不用柯里化

直接给onChange赋值一个回调函数,在回调函数体里调用saveFormData('字段名', event),这样也实现了传入要修改的字段名的效果

js 复制代码
<body>
	<!-- 准备好一个"容器" -->
	<div id="test"></div>
	
	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		//创建组件
		class Login extends React.Component{
			//初始化状态
			state = {
				username:'', //用户名
				password:'' //密码
			}

			//保存表单数据到状态中
			saveFormData = (dataType,event)=>{
				this.setState({[dataType]:event.target.value})
			}

			//表单提交的回调
			handleSubmit = (event)=>{
				event.preventDefault() //阻止表单提交
				const {username,password} = this.state
				alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
			}
			render(){
				return(
					<form onSubmit={this.handleSubmit}>
						用户名:<input onChange={event => this.saveFormData('username',event) } type="text" name="username"/>
						密码:<input onChange={event => this.saveFormData('password',event) } type="password" name="password"/>
						<button>登录</button>
					</form>
				)
			}
		}
		//渲染组件
		ReactDOM.render(<Login/>,document.getElementById('test'))
	</script>
</body>
相关推荐
Json_1817901448018 分钟前
电商拍立淘按图搜索API接口系列,文档说明参考
前端·数据库
风尚云网41 分钟前
风尚云网前端学习:一个简易前端新手友好的HTML5页面布局与样式设计
前端·css·学习·html·html5·风尚云网
木子020443 分钟前
前端VUE项目启动方式
前端·javascript·vue.js
GISer_Jing1 小时前
React核心功能详解(一)
前端·react.js·前端框架
捂月1 小时前
Spring Boot 深度解析:快速构建高效、现代化的 Web 应用程序
前端·spring boot·后端
深度混淆1 小时前
实用功能,觊觎(Edge)浏览器的内置截(长)图功能
前端·edge
Smartdaili China1 小时前
如何在 Microsoft Edge 中设置代理: 快速而简单的方法
前端·爬虫·安全·microsoft·edge·社交·动态住宅代理
秦老师Q1 小时前
「Chromeg谷歌浏览器/Edge浏览器」篡改猴Tempermongkey插件的安装与使用
前端·chrome·edge
滴水可藏海1 小时前
Chrome离线安装包下载
前端·chrome
endingCode1 小时前
45.坑王驾到第九期:Mac安装typescript后tsc命令无效的问题
javascript·macos·typescript