函數式
JavaScript是以函數為一等公民的函數式語言。函數在JavaScript中也是一個對象(繼承制Function),函數也可以作為參數傳遞成函數變量。最近幾年函數式也因為其無副作用的特性、透明性、惰性計算等在高並發,大數據領域火起來了。
JavaScript中也有如Underscore、lodash之類的函數式庫,如lodash的使用方式:
var names = _.chain(users)
.map(function(user){
return user.user;
})
.join(" , ")
.value();
console.log(names);
關於lodash更多內容請參考JavaScript工具庫之Lodash.
柯里化
今天文章將以高階函數中的柯里化方式來,看看JavaScript的函數式能力。
在計算機科學中,柯里化(Currying)是把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,並且返回接受余下的參數且返回結果的新函數的技術。這個技術由 Christopher Strachey 以邏輯學家 Haskell Curry 命名的,盡管它是 Moses Schnfinkel 和 Gottlob Frege 發明的。
在理論計算機科學中,柯里化提供了在簡單的理論模型中比如只接受一個單一參數的lambda 演算中研究帶有多個參數的函數的方式。
JavaScript的柯里化實現
下邊的例子,我們將把柯里化方式泛化為接受任意個參數,直到聲明的方法參數個數飽和才執行,所以根據參數個數可以有多種柯里化函數產生。
代碼如下:
(function(global) {
var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m,
FN_ARG_SPLIT = /,/,
FN_ARG = /^\s*(_?)(\S+?)\1\s*$/,
STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
var getArgLength = function(func) {
var fnText = func.toString().replace(STRIP_COMMENTS, '');
var argDecl = fnText.match(FN_ARGS);
var params = [];
argDecl[1].split(FN_ARG_SPLIT).forEach(function(arg) {
arg.replace(FN_ARG, function(all, underscore, name) {
params.push(name);
});
});
return params.length;
};
var curryFunc = function(func, len) {
len = len || getArgLength(func);
var args = [];
if (len === 0) {
return func.apply(null);
}
return function() {
[].push.apply(args, [].slice.apply(arguments));
if (args.length >= len) {
return func.apply(null, args);
}
return arguments.callee;
};
};
global.curryFunc = curryFunc;
})(this);
function add(x, y, z) {
return x + y + z;
}
console.log("result 1:", curryFunc(add)(1, 2)(3));
console.log("result 2:", curryFunc(add)(1)(2, 3));
console.log("result 3:", curryFunc(add)(1)(3)(2));
function add(x, y, z) {
return x * y * z;
}
console.log("result 1:", curryFunc(add)(2, 4)(6));
console.log("result 2:", curryFunc(add)(2)(4, 6));
console.log("result 3:", curryFunc(add)(2)(6)(4));
function sayHello() {
return "hello";
}
console.log(curryFunc(sayHello));
首先上面會利用正則來獲取傳入函數的參數個數。再返回一個函數的代理,每次的調用都會將傳入參數緩存在args臨時變量中,直到參數個數飽和才會立即執行。代碼比較冗長,慢慢品味,當然有不足之處,也希望大家指出來。
