亮神知识库 亮神知识库
首页
  • 手写代码

    • 手写代码系列
  • 基础知识

    • 基础
    • JS底层
    • CSS
  • 原理
  • 浏览器
  • HTTP
  • 网络安全
  • babel
  • webpack基础
  • webpack进阶
  • Vite
  • TypeScript
  • Vue2
  • Vue3
  • Node基础

    • glob
    • 模块化机制
    • 事件循环
    • KOA2框架原理
    • Node子进程
    • cluster原理(了解)
  • 教育行业2021

    • B端
    • C端
    • 工具
  • 游戏行业2025
  • 刷题
  • 杂(待整理)
  • 学习
  • 面试
  • 实用技巧
  • 心情杂货
  • 年度总结
  • 友情链接
关于
  • 分类
  • 标签
  • 归档
  • 收藏
GitHub (opens new window)

亮神

前程明亮,未来可期
首页
  • 手写代码

    • 手写代码系列
  • 基础知识

    • 基础
    • JS底层
    • CSS
  • 原理
  • 浏览器
  • HTTP
  • 网络安全
  • babel
  • webpack基础
  • webpack进阶
  • Vite
  • TypeScript
  • Vue2
  • Vue3
  • Node基础

    • glob
    • 模块化机制
    • 事件循环
    • KOA2框架原理
    • Node子进程
    • cluster原理(了解)
  • 教育行业2021

    • B端
    • C端
    • 工具
  • 游戏行业2025
  • 刷题
  • 杂(待整理)
  • 学习
  • 面试
  • 实用技巧
  • 心情杂货
  • 年度总结
  • 友情链接
关于
  • 分类
  • 标签
  • 归档
  • 收藏
GitHub (opens new window)
  • 基础

  • 手写代码

    • 手写类型转换
    • 手写累加、累乘函数
    • 手写new
    • 手写深拷贝
    • 手写Object.create
    • 手写继承
    • 手写extends
    • 手写instanceof
    • 手写call、apply、bind
    • 手写jsonp
    • 手写getQueryString
    • 手写setInterval
    • 手写防抖与节流
    • 手写对象属性值迭代器
    • 手写分时函数
    • 手写事件委托
    • 手写图片懒加载
    • 手写原生Ajax请求
    • 手写AOP装饰函数
    • 手写柯里函数
      • 应用场景
    • 手写数组扁平化flat
    • 手写数组去重
    • 手写eventEmit类
    • 手写Vue数据响应式
    • 手写Vue nextTick
    • 手写Promise
  • JS底层深入

  • CSS

  • 基础
  • 手写代码
0zcl
2021-06-18
目录

手写柯里函数

  • 计算机科学中的定义 (opens new window):柯里化是一种将使用多个参数的一个函数转换成一系列使用一个参数的函数的技术.
  • JS中的定义 (opens new window):当函数有多个参数的时候,我们可以对函数进行改造。我们可以调用一个函数,只传递部分的参数(这部分参数以后永远不变),然后让这个函数返回一个新的函数。新的函数传递剩余的参数,并且返回相应的结果
function add(a, b, c) {
  return a + b + c
}
add(1, 2, 3)
// 假设有一个 curry 函数可以做到柯里化, 返回一个新的函数addCurry
var addCurry = curry(add)
addCurry(1)(2)(3)
addCurry(1)(2, 3)
addCurry(1, 2)(3)
1
2
3
4
5
6
7
8
9

注意

实现curry函数

答:

function curry(fn) {
  let args = []
  return function() {
    args = args.concat([...arguments])
    if (args.length >= fn.length) { // 终止条件
      const res = fn.apply(this, args)
      args = [] // 清空收集的参数
      return res
    } else {
      return arguments.callee
    }
  }
}
// 测试
function add(a, b, c) {
  return a + b + c
}
var addCurry = curry(add)
addCurry(1)(2)(3) // 6
addCurry(1)(2, 3) // 6
addCurry(1, 2)(3) // 6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

思路:闭包把参数保存起来,当参数的数量足够执行函数了,就开始执行函数

  1. curry柯里化 传入函数A,柯里化后返回一个新的函数
  2. 利用闭包,收集参数
  3. 使用递归。如果闭包收集的参数与函数A的参数相同【终止条件】,则执行函数A,如果小于,则返回一个函数,继续收集参数,直到达到终止条件,跳出递归

注意点:

  1. 使用arguments.callee (opens new window),调用匿名函数本身
  2. 达到终止条件时,会清空收集的参数。否则多次调用<code>addCurry(1)(2)(3)</code>会出错。

error

这是因为执行<code>addCurry(1)(2)(3)</code>此时args为[1,2,3],再执行<code>addCurry(1)(2, 3)</code>,addCurry(1)返回6,并不是函数,因此爆错。故这里我加了清空, 但还是有问题的,比如执行下方的应用场景

最终版:

function curry(fn) {
  return function curriedFn() {
    const args = [...arguments]
    if (args.length >= fn.length) { // 终止条件
      return fn.apply(this, args)
    } else {
      return function() {
        return curriedFn.apply(this, args.concat([...arguments]))
      }
    }
  }
}
// 测试
function add(a, b, c) {
  return a + b + c
}
var addCurry = curry(add)
addCurry(1)(2)(3) // 6
addCurry(1)(2, 3) // 6
addCurry(1, 2)(3) // 6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

思路与上面基本一致的,只是改进了收集参数的方式。

# 应用场景

工作中经常遇到各种需要正则校验的需求,一般我们会这样做:

// 非柯里化版本
function checkByRegExp(regExp,string) {
  return regExp.test(string);  
}

checkByRegExp(/^1\d{10}$/, '15010001000'); // 校验电话号码
checkByRegExp(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/, '[email protected]'); // 校验邮箱
1
2
3
4
5
6
7

缺点:某个电话号的正则检验出现了改变,就需要去修改<code>checkByRegExp(/^1\d{10}$/, '15010001000')</code>,代码中有100处使用到了电话较验,那就得 修改100个地方了!! 这显然存在冗余!

能不能只修改一个地方的电话正则即可?

//进行柯里化
let _check = curry(checkByRegExp);
//生成工具函数,验证电话号码
let checkCellPhone = _check(/^1\d{10}$/);
//生成工具函数,验证邮箱
let checkEmail = _check(/^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/);

checkCellPhone('18642838455'); // 校验电话号码
checkEmail('[email protected]'); // 校验邮箱
1
2
3
4
5
6
7
8
9

参考: 【深入理解】柯里化&手写 Lodash 中 curry 函数| 技术点评 (opens new window) JavaScript专题之函数柯里化 (opens new window)

编辑 (opens new window)
上次更新: 2025/07/20, 06:21:22
手写AOP装饰函数
手写数组扁平化flat

← 手写AOP装饰函数 手写数组扁平化flat→

最近更新
01
2024年
07-20
02
2023年
07-20
03
2022年
07-20
更多文章>
Theme by Vdoing | Copyright © 2025-2025 亮神 | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式