目录
- 函数柯里化的实现
- 柯里化的作用
一、函数柯里化的实现
柯里化函数就是高阶函数的一种,好处主要是实现参数的复用和延迟执行,不过性能上就会没那么好,要创建数组存参数,要创建闭包,而且存取argements比存取命名参数要慢一点
实现
add(1)(2)(3)要求参数不固定,类似add(1)(2, 3, 4)(5)()这样也行,我这实现的是中间的不能不传参数,最后一个不传参数,以此来区分是最后一次调用然后累计结果
1) 实现一
// 每次调用的传进来的参数做累计处理
function reduce (...args) {
return args.reduce((a, b) => a + b)
}
function currying (fn) {
// 存放每次调用的参数
let args = []
return function temp (...newArgs) {
if (newArgs.length) {
// 有参数就合并进去,然后返回自身
args = [ ...args, ...newArgs ]
return temp
} else {
// 没有参数了,也就是最后一个了,执行累计结果操作并返回结果
let val = fn.apply(this, args)
args = [] //保证再次调用时清空
return val
}
}
}
let add = currying(reduce)
console.log(add(1)(2, 3, 4)(5)()) //15
console.log(add(1)(2, 3)(4, 5)()) //15
1) 实现二
当接收的参数数量与原函数的形参数量相同时,执行原函数; 当接收的参数数量小于原函数的形参数量时,返回一个函数用于接收剩余的参数,直至接收的参数数量与形参数量一致,执行原函数。
function curry(fn){
if(fn.length <=1){return fn}
var returnFn = (...args) => {
//console.log(...args,typeof ...args);
if(fn.length === args.length){
//参数都传齐时
return fn(...args)
}else{
//参数没传齐时,就返回一个函数
return (...args2) => {
console.log(args2," ",args);
return returnFn(...args,...args2)
}
}
}
return returnFn
}
var add = (a,b,c,d) => a+b+c+d;
//包装add
var returnFn = curry(add);
// 递归传递参数给returnFn
var returnFnArrowFn = returnFn(1)(2)(3);
// 参数传齐,returnFn将参数传递给输入函数fn, 并调用fn
returnFnArrowFn(4);// 10
二、ajax
// 这是调用下面函数的结构,这个结果大家应该很熟悉,就不解释了,应该都用过
myAjax({
type: "get",
url: "https://xxx",
data: { name: "沐华", age:18 },
dataType: "json",
async: true,
success:function(data){
console.log(data);
},
error:function(){
alert('报错');
}
})
// 定义一个将 { name: "沐华", age:18 } 转成 name=沐华&age=18 这种格式的方法
function fn(data){
let arr = []
for(let i in data){
arr.push( i+'='+data[i])
}
return arr.join('&')
}
// 下面就是实现上面调用和传参的函数
function myAjax(options){
let xhr = null
let str = fn(options.data)
// 创建 xhr
if(window.XMLHttpRequest){
xhr = new XMLHttpRequest()
}else{
xhr = new ActiveXObject('Microsoft,XMLHTTP')
}
// 这里只配置了 get 和 post
if(options.type === 'get' && options.data !== undefined){
// 创建 http 请求
xhr.open(options.type, options.url+'?'+str, options.async || true)
// 发送请求
xhr.send(null)
}else if(options.type === 'post' && options.data !== undefined){
xhr.open(options.type, options.url, options.async || true)
// 设置请求头
xhr.setRequestHeaders('Content-type','application/x-www-form-urlencoede')
xhr.send(str)
}else{
xhr.open(options.type, options.url, options.async || true)
xhr.send(null)
}
// 监听状态
xhr.onreadystatechange = function(){
if(xhr.readyState === 4 && xhr.status === 200){
let res = xhr.responseText
try{
if(options.success === undefined){
return xhr.responseText
}else if(typeof res === 'object'){
options.success(res)
}else if(options.dataType === 'json'){
options.success(JSON.parse(res))
}else{
throw new Error()
}
}catch(e){
if(options.error !== undefined){
options.error()
throw new Error()
}else{
throw new Error()
}
}
}
}
}
二 柯里化的作用
柯里化是一种将使用
多个参数的一个函数转换成一系列使用一个参数的函数的技术。
举例来说,一个接收3个参数的普通函数,在进行柯里化后, 柯里化版本的函数接收一个参数并返回接收下一个参数的函数, 该函数返回一个接收第三个参数的函数。 最后一个函数在接收第三个参数后, 将之前接收到的三个参数应用于原普通函数中,并返回最终结果。
柯里化实际是把简答的问题复杂化了,但是复杂化的同时,我们在使用函数时拥有了更加多的自由度。 而这里对于函数参数的自由处理,正是柯里化的核心所在。
柯里化本质上是降低通用性,提高适用性
1) 柯里化的这种用途可以被理解为:参数复用
function checkByReg(regExp,string) {
return regExp.test(string);
}
checkByReg(/^1\d{10}$/, '18612345678'); // 校验电话号码
checkByReg(/^1\d{10}$/, '18612345679'); // 校验电话号码
checkByReg(/^1\d{10}$/, '18612345676'); // 校验电话号码
checkByReg(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, 'test@qq.com'); // 校验邮箱
把函数checkByRegExp 柯里化后, 就可以 实现参数复用.
参数复用 伪代码
function checkByReg(regExp,string) {
return regExp.test(string);
}
let curryCheck = curry(checkByReg);
let CheckPhone = curryCheck(/^1\d{10}$/); // 参数复用
CheckPhone('18612345678');