標籤:
函數式
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臨時變數中,直到參數個數飽和才會立即執行。代碼比較冗長,慢慢品味,當然有不足支援,也希望大家指出來。
JavaScript函數柯裡化