一道add面试题的解法
函数柯里化
函数柯里化是指一个函数接收函数A作为参数,运行后能够返回新函数,这个新函数能够处理函数A的剩余参数。参照
// 简单实现,参数只能从右到左传递
function createCurry(func, args) {
var arity = func.length;
var args = args || [];
return function() {
var _args = [].slice.call(arguments);
[].push.apply(_args, args);
// 如果参数个数小于最初的func.length,则递归调用,继续收集参数
if (_args.length < arity) {
return createCurry.call(this, func, _args);
}
// 参数收集完毕,则执行func
return func.apply(this, _args);
}
}
柯里化思路解决最常见的一个面试题
add(1)(2)(3) == 6;
add(1, 2, 3)(4) == 10;
add(1)(2)(3)(4)(5) ==15;
add(1)(2)(3)(4)(5) + 1 == 16
这个是根据柯里化衍生出来的题目。add函数并不接收函数,它只是接收参数,它能够返回一个新函数,这个函数的功能和add一样,继续接收参数。所以我们只要定义一个函数,返回一个新函数,这个函数能够接收参数,并在toString时候转换为数字。
下面是网上给出的写法
function add () {
let args = [].slice.call(arguments)
function adder () {
var _add = function () {
args.push(...arguments)
return _add
}
_add.toString = function () {
return args.reduce((i, item) => i + item)
}
return _add
}
return adder(...args)
}
实际上,这个和柯里面化没有什么关系,应该说是链式调用的一种方式。由于我们要保存参数,第一次执行时返回的是内部的_add函数,_add因为使用了闭包,可以访问我们最开始生成的一个数组,每次把新的参数加入到数组中。使用toString保证在运算时会自动进行运算。
其他解法
bind方法也是返回一个函数,只是函数是隐式返回的。既然是返回函数形成链式调用,那么用bind也可以达到效果。下面是一种实现
function add () {
var args = [].slice.call(arguments)
add.toString = function () {
return args.reduce((i, item) => i + item)
}
return add.bind(null,...args)
}
调用下看下
add(1)(2)(3)(4) // 10
add(1)(2)(3)(4) + 1 // function () { [native code] }1
结果只是部分达到了我们的预期。由于bind方法返回的是一个新方法,在console.log()时候可能针对bind进行了进一步执行,而在加法的隐式转换中则无法实现。因此改进下:
function add () {
var args = [].slice.call(arguments)
var func = add.bind(null, ...arguments)
func.toString = function () {
return args.reduce((i, item) => i + item)
}
return func
}
add(1)(2)(3)(4)
// ƒ add() {
// var args = [].slice.call(arguments)
// var func = add.bind(null, ...arguments)
// func.toString = function () {
// return args.reduce((i, item) => i + item)
// }
// return func
// }
add(1)(2)(3)(4) + 1 // 11
可以发现,隐式转换生效了,但我们log出来却是add函数本身。所以再给add加一层
function add () {
var args = [].slice.call(arguments)
var func = add.bind(null, ...arguments)
add.toString = func.toString = function () {
return args.reduce((i, item) => i + item)
}
return func
}
add(1)(2)(3)(4) + 1 // 11
add(1)(2)(3)(4) // 10
结果就可以实现了。这种bind方法实际上就是把原来的闭包存储的参数转换到从arguments中存储。由于bind要不停上创建函数,理论上性能会差一些,但代码更容易理解一些。

浙公网安备 33010602011771号