javascript - 「前端面试题系列6」理解函数的柯里化 - 超哥前端小栈 - SegmentFault 思否
维基百科上说道:柯里化,英语:Currying,是把接受多个参数的函数变换成接受一个单一参数的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
也就是,函数套函数,返回一个函数,剩余参数放子函数
// 普通的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
柯里化的作用就是,参数复用,延迟执行。
Function.prototype.bind = function (context) {
var _this = this
var args = Array.prototype.slice.call(arguments, 1)
return function() {
return _this.apply(context, args)
}
}
js中经常使用的bind,实现的机制就是Currying
实现:
彻底搞懂闭包,柯里化,手写代码,金九银十不再丢分! - 掘金
一、固定长度参数的柯里化
function curry(fn) {
// 获取原函数的参数长度
const argLen = fn.length;
// 跳过序号0,从序号为1开始截取参数,转成数组,保存下来
const presetArgs = [].slice.call(arguments, 1)
// 返回一个新函数
return function() {
// 新函数调用时会继续传参,整个转成数组保存
const restArgs = [].slice.call(arguments)
const allArgs = [...presetArgs, ...restArgs]
if (allArgs.length >= argLen) {
// 如果参数够了,就执行原函数
return fn.apply(this, allArgs)
} else {
// 否则继续柯里化
return curry.call(null, fn, ...allArgs)
}
}
}
let m = curry(add)
let v=m(1,1)(1)
console.log(v)
二、动态参数长度的柯里化(推荐)
我怎么知道最后执行的时机?其实,这里有个忍者技艺:valueOf
和toString
。
js在获取当前变量值的时候,会根据语境,隐式调用valueOf
和toString
方法进行获取需要的值。
function curry(fn) {
// 跳过序号0,从序号为1开始截取参数,转成数组,保存下来
const presetArgs = [].slice.call(arguments, 1)
// 返回一个新函数
function curried () {
// 新函数调用时会继续传参
const restArgs = [].slice.call(arguments)
const allArgs = [...presetArgs, ...restArgs]
return curry.call(null, fn, ...allArgs)
}
// 重写toString
curried.toString = function() {
return fn.apply(null, presetArgs)
}
//数值类型
curried.valueOf = function(){
return fn.apply(null, presetArgs);
}
return curried;
}
function dynamicAdd() {
const args = [].slice.call(arguments)
return args.reduce((prev, curr) => {
return prev + curr
}, 0)
}
var add = curry(dynamicAdd);
let y1 = add(1)(2)(3)(4) // 10
let y2 = add(1, 2)(3, 4)(5, 6) // 21
console.log(y1.toString())
console.log(y2.toString())