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)
數組這些方法應該也是通過索引來訪問元素實現的。