函数式编程笔记 柯里化示例1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 var adder = function ( ) { var _args = []; return function ( ) { if (arguments .length === 0 ) { return _args.reduce(function (a, b ) { return a + b; }); } [].push.apply(_args, [].slice.call(arguments )); return arguments .callee; } }; var sum = adder();console .log(sum); sum(100 ,200 )(300 ); sum(400 ); console .log(sum());
柯里化示例2 currying 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 var currying = function (fn ) { var _args = []; return function ( ) { if (arguments .length === 0 ) { return fn.apply(this , _args); } Array .prototype.push.apply(_args, [].slice.call(arguments )); return arguments .callee; } }; var multi=function ( ) { var total = 0 ; for (var i = 0 , c; c = arguments [i++];) { total += c; } return total; }; var sum = currying(multi); sum(100 ,200 )(300 ); sum(400 ); console .log(sum());
柯里化示例3 柯里化的基础 上面的代码(示例2)其实是一个高阶函数(high-order function), 高阶函数是指操作函数的函数,它接收一个或者多个函数作为参数,并返回一个新函数。此外,还依赖与闭包的特性,来保存中间过程中输入的参数。即: 函数可以作为参数传递 函数能够作为函数的返回值 闭包 柯里化的作用
1 2 3 4 5 6 7 8 9 10 11 var addEvent = function (el, type, fn, capture ) { if (window .addEventListener) { el.addEventListener(type, function (e ) { fn.call(el, e); }, capture); } else if (window .attachEvent) { el.attachEvent("on" + type, function (e ) { fn.call(el, e); }); } };
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var addEvent = (function ( ) { if (window .addEventListener) { return function (el, sType, fn, capture ) { el.addEventListener(sType, function (e ) { fn.call(el, e); }, (capture)); }; } else if (window .attachEvent) { return function (el, sType, fn, capture ) { el.attachEvent("on" + sType, function (e ) { fn.call(el, e); }); }; } })();
Function.prototype.bind 方法也是柯里化应用 与 call/apply 方法直接执行不同,bind 方法 将第一个参数设置为函数执行的上下文,其他参数依次传递给调用方法(函数的主体本身不执行,可以看成是延迟执行),并动态创建返回一个新的函数, 这符合柯里化特点。
1 2 3 4 5 var foo = {x : 888 };var bar = function ( ) { console .log(this .x); }.bind(foo); bar();
下面是一个 bind 函数的模拟,testBind 创建并返回新的函数,在新的函数中将真正要执行业务的函数绑定到实参传入的上下文,延迟执行了。
1 2 3 4 5 6 7 8 9 Function .prototype.testBind = function (scope ) { var fn = this ; return function ( ) { return fn.apply(scope); } }; var testBindBar = bar.testBind(foo); console .log(testBindBar); testBindBar();
这里要注意 prototype 中 this 的理解。
组合 compose 示例1
1 2 3 4 5 var compose = function (f,g ) { return function (x ) { return f(g(x)); }; };
1 2 3 4 var toUpperCase = function (x ) { return x.toUpperCase(); };var exclaim = function (x ) { return x + '!' ; };var shout = compose(exclaim, toUpperCase);shout("send in the clowns" );
1 2 3 var shout = function (x ) { return exclaim(toUpperCase(x)); };
示例2
1 2 3 4 5 6 var head = function (x ) { return x[0 ]; };var reverse = reduce(function (acc, x ) { return [x].concat(acc); }, []);var last = compose(head, reverse);last(['jumpkick' , 'roundhouse' , 'uppercut' ]);
** head ** 取第一个元素,** reverse **反转元素序列
1 2 3 var associative = compose(f, compose(g, h)) == compose(compose(f, g), h);
compose 的调用分组不重要,所以结果都是一样的
1 2 3 4 compose(toUpperCase, compose(head, reverse)); compose(compose(toUpperCase, head), reverse);
1 2 3 4 5 6 7 8 9 10 11 12 var lastUpper = compose(toUpperCase, head, reverse);lastUpper(['jumpkick' , 'roundhouse' , 'uppercut' ]); var loudLastUpper = compose(exclaim, toUpperCase, head, reverse)loudLastUpper(['jumpkick' , 'roundhouse' , 'uppercut' ]);
1 2 3 4 5 6 7 8 9 10 11 12 var loudLastUpper = compose(exclaim, toUpperCase, head, reverse);var last = compose(head, reverse);var loudLastUpper = compose(exclaim, toUpperCase, last);var last = compose(head, reverse);var angry = compose(exclaim, toUpperCase);var loudLastUpper = compose(angry, last);
pointerfree 1 2 3 4 5 6 7 var snakeCase = function (word ) { return word.toLowerCase().replace(/\s+/ig , '_' ); }; var snakeCase = compose(replace(/\s+/ig , '_' ), toLowerCase);
示例
1 2 3 4 5 6 7 8 9 var initials = function (name ) { return name.split(' ' ).map(compose(toUpperCase, head)).join('. ' ); }; var initials = compose(join('. ' ), map(compose(toUpperCase, head)), split(' ' ));initials("hunter stockton thompson" );
debug 组合的一个常见错误是,在没有局部调用之前,就组合类似 map 这样接受两个参数的函数。
1 2 3 4 5 6 7 8 9 10 11 var latin = compose(map, angry, reverse);latin(["frog" , "eyes" ]); var latin = compose(map(angry), reverse);latin(["frog" , "eyes" ]);
http://www.2cto.com/kf/201412/357997.html
https://www.gitbook.com/book/llh911001/mostly-adequate-guide-chinese/details