手写柯里化累加器
create by db on 2021-5-27 18:26:30
Recently revised in 2021-5-27 18:26:34闲时要有吃紧的心思,忙时要有悠闲的趣味
前言
面试必问,不说废话。
正文
一、柯里化(Currying)
柯里化(Currying)是把接受多个参数的函数转变为单一参数的函数,并且返回接受余下的参数且返回结果的新函数的技术。
解释
-
通过闭包管理
-
支持链式调用
-
每次运行返回一个 function
即:通过将多个参数换成一个参数,每次运行返回新函数的技术
举例
// 普通的add函数
function add(x, y) {
return x + y
}
// Currying后
function curryingAdd(x) {
return function (y) {
return x + y
}
}
add(1, 2) // 3
curryingAdd(1)(2) // 3。
复制代码
应用场景
1. 参数复用
在一个正则的校验中,正常来说直接调用 check 函数就可以了,但是如果我有很多地方都要校验是否有数字,其实就是需要将第一个参数 reg 进行复用,这样别的地方就能够直接调用 hasNumber,hasLetter 等函数,让参数能够复用,调用起来也更方便。
// 正常正则验证字符串 reg.test(txt)
// 函数封装
function check(reg, txt) {
return reg.test(txt)
}
// 校验数字
check(/\d+/g, 'test') // false
// 校验字母
check(/[a-z]+/g, 'test') // true
// Currying后
function curryingCheck(reg) {
return function (txt) {
return reg.test(txt)
}
}
// 校验数字
var hasNumber = curryingCheck(/\d+/g)
// 校验字母
var hasLetter = curryingCheck(/[a-z]+/g)
hasNumber('test1') // true
hasNumber('testtest') // false
hasLetter('21212') // false
复制代码
2. 返回函数,延迟运行
像我们 js 中经常使用的 bind,实现的机制就是 Currying.
Function.prototype.bind = function (context) {
var _this = this
var args = Array.prototype.slice.call(arguments, 1)
return function () {
return _this.apply(context, args)
}
}
复制代码
二、柯里化累加器
经典面试题,柯里化累加器
// 实现一个add方法,使计算结果能够满足如下预期:
add(1)(2)(3) = 6;
add(1, 2, 3)(4) = 10;
add(1)(2)(3)(4)(5) = 15;
复制代码
1. 确定参数的函数柯里化实现
// 累加函数,只能传四个参数
function add(a, b, c, d) {
return a + b + c + d
}
// 柯里化函数
function curry(fn) {
return function add(...args) {
if (args.length < fn.length) {
// 判断接受的参数是否小于函数的参数长度
return function () {
// 参数不够长度,再次接受传递参数
return add(...args, ...arguments)
}
}
return fn(...args) // 不要求改变this
}
}
let curried = curry(add)
console.log(curried(1)(2)(3)(4)) //10
console.log(curried(1, 2)(2, 4)) //9
复制代码
2.不确定参数实现无限累加
// 累加函数,参数不限
function add(arr) {
return arr.reduce((acc, item) => {
return acc + item
})
}
// 柯里化函数
function curry(fn) {
let parmas = []
return function add(...args) {
if (args.length) {
//判断是否有参数
parmas = [...parmas, ...args]
return add
}
return fn(parmas)
}
}
let curried = curry(add)
console.log(curried(1)(2)(3)(4)(10, 20)()) //40
// 注意最后的调用用方式,()调用不传递参数,会跳出判断,调用累加函数
复制代码
3.一个函数实现不确定参数无限累加
function add() {
// 第一次执行时,定义一个数组专门用来存储所有的参数
const argList = Array.from(arguments)
// 在内部声明一个函数,利用闭包的特性保存_args并收集所有的参数值
const calculate = function () {
argList.push(...arguments)
return calculate
}
// 利用隐式转换的特性,当最后执行时隐式转换,并计算最终的值返回
calculate.toString = function () {
return argList.reduce((a, b) => a + b, 0)
}
return calculate
}
// 实现一个 add 方法,使计算结果能够满足以下预期
console.log(add(1)(2)(3)) // 6
console.log(add(1, 2, 3)(4)) // 10;
console.log(add(1)(2)(3)(4)(5)) // 15;
var a = add(1)(2)(3)(4) // f 10
var b = add(1, 2, 3, 4) // f 10
var c = add(1, 2)(3, 4) // f 10
var d = add(1, 2, 3)(4) // f 10
// 可以利用隐式转换的特性参与计算
console.log(a + 10) // 20
console.log(b + 20) // 30
console.log(c + 30) // 40
console.log(d + 40) // 50
// 也可以继续传入参数,得到的结果再次利用隐式转换参与计算
console.log(a(10) + 100) // 120
console.log(b(10) + 100) // 120
console.log(c(10) + 100) // 120
console.log(d(10) + 100) // 120
复制代码
Tips
要补充的知识点是函数的隐式转换。当我们直接将函数参与其他的计算时,函数会默认调用 toString 方法,直接将函数体转换为字符串参与计算。
function fn() {
return 20
}
console.log(fn + 10) // 输出结果 function fn() { return 20 }10
复制代码
而为了打印出我们想要的结果我们就需要自己重写 toString 方法
function fn() {
return 20
}
fn.toString = function () {
return 30
}
console.log(fn + 10) // 40
复制代码
除此之外,当我们重写函数的 valueOf 方法也能够改变函数的隐式转换结果。
function fn() {
return 20
}
fn.valueOf = function () {
return 60
}
console.log(fn + 10) // 70
复制代码
当我们同时重写函数的 toString 方法与 valueOf 方法时,最终的结果会取 valueOf 方法的返回结果。
function fn() {
return 20
}
fn.valueOf = function () {
return 50
}
fn.toString = function () {
return 30
}
console.log(fn + 10) // 60
复制代码
总结
路漫漫其修远兮,与诸君共勉。
参考文献
- javascript 函数 add(1)(2)(3)(4)实现无限极累加 —— 一步一步原理解析 | CSDN-weixin_33778544
- add()无限调用 | CSDN-微笑边缘的金元宝
- 函数柯里化实现 add(1)(2)(3)(4)…无限累加 | CSDN-宝宝不是码农
后记:Hello 小伙伴们,如果觉得本文还不错,记得点个赞或者给个 star,你们的赞和 star 是我编写更多更丰富文章的动力!GitHub 地址
文档协议
db 的文档库 由 db 采用 知识共享 署名-非商业性使用-相同方式共享 4.0 国际 许可协议进行许可。
基于github.com/danygitgit上的作品创作。
本许可协议授权之外的使用权限可以从 creativecommons.org/licenses/by… 处获得。
























![[桜井宁宁]COS和泉纱雾超可爱写真福利集-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/4d3cf227a85d7e79f5d6b4efb6bde3e8.jpg)

![[桜井宁宁] 爆乳奶牛少女cos写真-一一网](https://www.proyy.com/skycj/data/images/2020-12-13/d40483e126fcf567894e89c65eaca655.jpg)