【高频面试题】函数柯里化的实现与ajax

1,894 阅读4分钟

目录

  1. 函数柯里化的实现
  2. 柯里化的作用

一、函数柯里化的实现

柯里化函数就是高阶函数的一种,好处主要是实现参数的复用和延迟执行,不过性能上就会没那么好,要创建数组存参数,要创建闭包,而且存取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');

参考