Open IWSR opened 5 years ago
这是一个典型的函数柯里化的知识点,其定义为将接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数。
此题的要求为sum(2)(3)实现与sum(2, 3)的效果【暂且这么认为吧,知识点就是柯理化】 由题意可归纳为以下要求
此时可以大致归纳为要求实现一个方法,该方法需要返回另外一个方法,且返回的方法需要保持对原有的函数作用域内某变量的引用,很熟悉的要求,就是个闭包的结构。 以下放出初步的实现
function sum() {
function add(a, b) {
return a + b
}
// slice会返回一个新数组,这不会影响到arguments
let args = Array.prototype.slice.call(arguments);
// 返回一个函数可以提供二次调用
return function() {
// 此处的arguments为第二次调用时传入的参数
let newArgs = args.concat(Array.prototype.slice.call(arguments))
return add.apply(this, newArgs)
}
}
但是这样的写法是局限的且不怎么好用,理由如下:
为了解决上面的问题,思路也很清晰,应该将add操作作为一个fn的形参交给使用者自己去定义,因此可得到下面的变种
// 改名为curry了
function curry(fn) {
// slice会返回一个新数组,这不会影响到arguments
let args = Array.prototype.slice.call(arguments, 1);
// 返回一个函数可以提供二次调用
return function() {
// 此处的arguments为第二次调用时传入的参数
let newArgs = args.concat(Array.prototype.slice.call(arguments))
return fn.apply(this, newArgs)
}
}
虽说fn成为了参数可以被自定义,但是缺陷也出现了,curry(add, a)(b)可满足sum(a, b) => sum(a)(b)的要求,但如果sum(a, b, c)那就只能凉凉,换句话说我们需要判断场景(fn的参数个数,以及当前已经传入的元素个数)来决定是返回一个可调用的函数还是fn的执行结果。
function sub_curry(fn) {
let args = [].slice.call(arguments, 1);
return function() {
return fn.apply(this, args.concat([].slice.call(arguments)));
};
}
function curry(fn, length) {
// 初始化时赋值为fn的形参个数,用以标示剩余需要传入参数的个数
length = length || fn.length;
const slice = Array.prototype.slice;
return function() {
if (arguments.length < length) {
const combined = [fn].concat(slice.call(arguments));
// length - arguments.length用以计数当前已传入的参数
return curry(sub_curry.apply(this, combined), length - arguments.length);
} else {
return fn.apply(this, arguments);
}
};
}
To:
https://github.com/IWSR
面试公司:
有赞
面试环节:
网上找的
问题:
sum(2, 3)实现sum(2)(3)的效果