1.函数的柯里化定义
创建已经设置好一个或多个参数的函数,基本方法是使用一个闭包返回一个函数。
2.经典面试题
实现一个add函数,完成以下功能:
console.log(add(1,2,3)); //6
console.log(add(1)(2)(3)); //6
要想创建出一个通式,很容易想到用递归来解决,但是递归需要一个结束条件,这里的结束条件怎么确定呢?
首先可以看一下console.log()函数的用法:
- 如果传入参数是一个函数,那么就会默认调用默认toString()方法,将函数的定义打印出来
- 如果定义了toString()或valueOf()方法,就会调用valueOf() > toString()方法,valueOf()优先级高于toString()方法
因此这里我们可以通过自定义toString()方法来模拟结束条件,方法如下:
function add(){
var args=Array.prototype.slice.call(arguments);
function adder(){
var newArgs=Array.prototype.slice.call(arguments);
args=args.concat(newArgs);
return adder; //每次调用后返回自身函数对象,可以进行连续调用
}
adder.toString=function(){
return args.reduce(function(previos,current){
return previos+current;
});
}
return adder;
}
主要的思路就是,利用闭包来保存每一次传入函数的参数到args变量中,并且返回adder函数自身,最后打印的时候调用函数对象的toString方法将所有的参数相加。
3.柯里化通式
柯里化通式可以传入一个函数和要绑定的参数,返回包装后的函数:
function curry(func){
var args=Array.prototype.slice.call(arguments,1);
return function(){
var newArgs=Array.prototype.slice.call(arguments);
args=args.concat(newArgs);
return func.apply(null,args); //调用func时要用apply调用,参数都包含在数组中
}
}
var sum=curry(function(){
var args=Array.prototype.slice.call(arguments);
return args.reduce(function(a,b){
return a+b;
});
},1);
console.log(sum(2,3));
4.实现函数柯里化的bind函数
实现函数柯里化的bind函数可以分两次传入参数,每次传入的参数都会通过闭包,保存在外部函数作用域内。
function bind(func,context){
var args=Array.prototype.slice.call(arguments,2);
return function(){
var newArgs=Array.prototype.slice.call(arguments);
args=args.concat(newArgs);
return func.apply(context,args);
}
}
var a={
name: 'jc',
print: function(){
var str=Array.prototype.join.call(arguments,' ');
console.log(this.name+' '+str);
}
};
var b=bind(a.print,a,'first');
b('second'); //jc first second
5.函数内部对象arguments
在函数体内可以通过arguments对象访问参数数组,但是arguments对象只是与数组相似,并不是Array的实例,可以通过索引访问参数,有length长度属性,不过可以通过call和apply间接调用数组的方法:
Array.prototype.slice.call(arguments)
[].slice.call(arguments)
数组这些方法应该也是通过索引来访问元素实现的。