【JavaScript】函数柯里化

【JavaScript】函数柯里化函数柯里化 Currying 是一种将多个参数的函数转换为单个参数函数的技术

大家好,欢迎来到IT知识分享网。

什么是函数柯里化

下文部分来自黑马程序员

函数柯里化 (Currying) 是一种将多个参数的函数转换为单个参数函数的技术。

转换完毕之后的函数:只传递函数的一部分参数来调用,让他返回一个新的函数去处理剩下的参数。

例子:

// 调整函数 sum function sum(num1, num2) { return num1 + num2 } ​ // 改写为 可以实现如下效果 console.log(sum(1)(2)) 

核心步骤:

  1. sum改为接收一个参数,返回一个新函数
  2. 新函数内部将参数1参数2累加并返回
 function sum(num1) { return function (num2) { return num1 + num2 } } 
面试回答:

什么是函数柯里化

  1. 函数柯里化是一种将多个参数的函数转换为单个参数函数的技术
  2. 转换完毕之后的函数只需要传递一部分参数进行调用,并且会返回一个新的函数去处理剩下的参数

柯里化面试题-全局变量

柯里化在面试的时候一般以笔试题出现,比如

需求:

 function sum(a, b, c, d, e) { return a + b + c + d + e } // 改写函数sum实现:参数传递到5个即可实现累加 // sum(1)(2)(3)(4)(5) // sum(1)(2,3)(4)(5) // sum(1)(2,3,4)(5) // sum(1)(2,3)(4,5) 

核心步骤:

  1. 接收不定长参数
  2. 存储已传递的参数
  3. 判断长度
    1. 满足5:累加
    2. 不满足:继续返回函数本身
 let nums = [] function currySum(...args) { nums.push(...args) if (nums.length >= 5) { return nums.reduce((prev, curv) => prev + curv, 0) } else { return currySum } } 
面试回答:

柯里化面试题-全局变量

  1. 定义数组保存参数
  2. 函数接收不定长参数
  3. 调用时将传入的参数,添加到数组中,并判断数组长度:
    1. 满足长度要求:累加并返回结果
    2. 未达到长度要求:继续返回函数本身

柯里化面试题-使用闭包

需求:

  1. 使用闭包将上一节代码中的全局变量,保护起来
  2. 支持自定义累加的参数个数
 function sumMaker(length){ // 逻辑略 } // 支持5个累加 const sum5 = sumMaker(5) // 支持7个累加 const sum7 = sumMaker(7) sum7(1,2,3)(4,5,6,7) 

核心步骤:

  1. 定义外层函数:
    1. 定义参数length
    2. 将全局变量迁移到函数内
  2. 定义内层函数:
    1. 参数长度判断,使用传入的参数length
    2. 直接复用上一节的逻辑,并返回
 function sumMaker(length) { let nums = [] function inner(...args) { nums.push(...args) if (nums.length >= length) { return nums.reduce((prev, curv) => prev + curv, 0) } else { return inner } } return inner } 
面试回答:

柯里化面试题-使用闭包

  1. 定义函数,接收参数,用来确定参数个数
  2. 内部将上一节的逻辑拷贝进去
  3. 返回原函数
  4. 通过这样的调整,可以让我们自定义参数的个数,并且没有上一节的全局变量数组

柯里化实际应用-类型判断

通过参数复用,实现一个类型判断生成器函数

需求:

  1. 将下列4个类型判断函数,改写为通过函数typeOfTest动态生成
 // 有如下4个函数 function isUndefined(thing) { return typeof thing === 'undefined' } function isNumber(thing) { return typeof thing === 'number' } function isString(thing) { return typeof thing === 'string' } function isFunction(thing) { return typeof thing === 'function' } ​ // 改为通过 typeOfTest 生成: const typeOfTest =function(){ // 参数 和 逻辑略 ​ } const isUndefined = typeOfTest('undefined') const isNumber = typeOfTest('number') const isString = typeOfTest('string') const isFunction = typeOfTest('function') ​ // 可以通过 isUndefined,isNumber,isString,isFunction 来判断类型: ​ isUndefined(undefined) // true isNumber('123') // false isString('memeda') // true isFunction(() => { }) // true 

核心步骤:

  1. typeOfTest接收参数type用来接收判断的类型
  2. 内部返回新函数,接收需要判断的值,并基于type进行判断
  3. 使用箭头函数改写为最简形式~~传送门-github
 const typeOfTest = (type) => { return (thing) => { return typeof thing === type } } 
面试回答:

柯里化实际应用-类型判断

  1. 定义函数,接收需要判断的类型名
  2. 内部返回一个新的函数,
    1. 新函数接收需要判断的具体的值
    2. 新函数内部根据外层函数传入的类型,以及传入的值进行判断并返回结果

柯里化实际应用-固定参数

依旧是一个参数复用的实际应用

需求:

  1. 将如下3个请求的函数(都是post请求),变为通过axiosPost函数动态生成
  2. 实现函数axiosPost
 // 项目开发中不少请求的 请求方法 是相同的,比如 axios({ url: 'url', method: 'get' }) axios({ url: 'url', method: 'get', params: { // } }) axios({ url: 'url', method: 'post', data: '' }) axios({ url: 'url', method: 'post', data: '', headers: { ​ } }) ​ // 固定请求参数,请求方法固定,其他参数从外部传递进来 // 需求: 实现方法requestWithMethod 支持如下调用 requestWithMethod('get')({ url: '', params: {}, headers: {} }) requestWithMethod('post')({ url: '', headers: {}, data: {} }) ​ 

核心步骤:

  1. 函数内部固定请求方法,post
  2. 函数内部调用axios发请求即可
  3. axios内部就是这样实现的
    1. 传送门-github:
 function requestWithMethod(method) { return (config) => { return axios({ method, ...config }) } } 
面试回答:

柯里化实际应用-固定参数

  1. 函数柯里化是一种函数式编程思想:将多个参数的函数转换为单个参数函数,调用时返回新的函数接收剩余参数
  2. 常见面试题,将函数改写为如下调用新式:核心思想就是返回新的函数,根据已经记录的参数长度判断:
    1. 长度符合要求:累加
    2. 长度不符合要求:继续返回
 function sum(a, b, c, d, e) { return a + b + c + d + e } // 改写函数sum实现:参数传递到5个即可实现累加 // sum(1)(2)(3)(4)(5) // sum(1)(2,3)(4)(5) // sum(1)(2,3,4)(5) // sum(1)(2,3)(4,5) 
  1. 常见应用:固定参数,比如axios中的:
    1. 类型判断函数
    2. get,post,put等别名方法
    3. 就用到了柯里化的思想

封装一个柯里化函数

// 柯里化函数 function carry() { 
    // 获取第一个参数,即函数 let fn = arguments[0]; // 获取剩余参数 let args = Array.prototype.slice.call(arguments, 1); // 判断参数是否已经全部传入 // fn.length 获取函数的参数长度 if (args.length === fn.length) { 
    // 如果已经全部传入参数,则直接执行函数 return fn.apply(this, args) } // 返回一个函数,该函数接收剩余参数 function _curry() { 
    // 将传入的参数与之前传入的参数合并 args.push(...arguments); // 判断参数是否已经全部传入 if (args.length === fn.length) { 
    return fn.apply(this, args) } // 递归调用 curry 函数,继续接收参数 return _curry } return _curry } function add(a, b, c) { 
    return a + b + c } console.log(carry(add, 1, 2, 3)) // 6  console.log(carry(add, 1)(2, 3)) // 6 console.log(carry(add, 1)(2)(3)) // 6 console.log(carry(add)(1, 2, 3)) // 6 

一道经典面试题

// add(1)(2)(3) // add(1, 2, 3)(4) // add(1)(2)(3)(4)(5) // 根据以上代码,实现一个add函数,要求使用函数柯里化 function add() { 
    // 将传入的所有参数转换为数组 let args = [...arguments] // 定义一个函数,用于接收新的参数,并返回一个新的函数 function calculator() { 
    // 将传入的新参数转换为数组 args.push(...arguments) return calculator } // 在calculator函数中定义toString方法,用于返回计算结果 calculator.toString = function () { 
    // 将数组中的所有参数相加并返回结果 return args.reduce((a, b) => a + b) } // 返回calculator函数,以便可以继续调用add函数进行计算 return calculator } console.log(add(1)(2)(3).toString()) console.log(add(1, 2, 3)(4).toString()) console.log(add(1)(2)(3)(4)(5).toString()) 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/116005.html

(0)
上一篇 2025-11-30 19:33
下一篇 2025-11-30 20:00

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信