[js] 柯里化(局部套用)(currying)
#参数复用
#
function curry(fn){ var args = Array.prototype.slice.call(arguments, 1); return function(){ //curriedAdd 这两个arguments是不同的,但是通过concat合并了 var innerArgs = Array.prototype.slice.call(arguments), finalArgs = args.concat(innerArgs); // 没有数组处理,实际上传进去的参数也就前边2个 return fn.apply(null, finalArgs); }; } function add(num1, num2){ console.log(arguments); return num1 + num2; } var curriedAdd = curry(add, 5); console.log(curriedAdd(3)); //8 var curriedAdd2 = curry(add, 5, 12); console.log(curriedAdd2()); //17
#
function spyOn(func) { var count = 0; var args = []; var results = []; var spy = function() { var innerArgs = Array.prototype.slice.call(arguments); args = args.concat(innerArgs); var result = func.apply(null,innerArgs);//第一个参数还可写this results = results.concat(result); count++; return result; }; spy.callCount = function() { return count; } spy.wasCalledWith = function(x) { return args.indexOf(x) > -1; } spy.returned = function(y) { return results.indexOf(y) > -1; } return spy; } function adder(n1, n2) { return n1 + n2; } var adderSpy = spyOn(adder); console.log(adderSpy(2, 4)); // returns 6 console.log(adderSpy(3, 5)); // returns 8 console.log(adderSpy.callCount()); // returns 2 console.log(adderSpy.wasCalledWith(4)); // true console.log(adderSpy.wasCalledWith(0)); // false console.log(adderSpy.returned(8)); // true console.log(adderSpy.returned(0)); // false
#
var currying = function(fn) { // fn 指官员消化老婆的手段 var args = [].slice.call(arguments, 1); // args 指的是那个合法老婆 return function() { // 已经有的老婆和新搞定的老婆们合成一体,方便控制 var newArgs = args.concat([].slice.call(arguments)); // 这些老婆们用 fn 这个手段消化利用,完成韦小宝前辈的壮举并返回 return fn.apply(null, newArgs); }; }; // 下为官员如何搞定7个老婆的测试 // 获得合法老婆 var getWife = currying(function() { var allWife = [].slice.call(arguments); // allwife 就是所有的老婆的,包括暗渡陈仓进来的老婆 console.log(allWife.join(";")); }, "合法老婆"); // 获得其他6个老婆 getWife("大老婆", "小老婆", "俏老婆", "***蛮老婆", "乖老婆", "送上门老婆"); // 换一批老婆 getWife("超越韦小宝的老婆");
#
var smallKenan = function(action) { console.log(arguments); var bigKenan = function(doing) { console.warn(arguments); var result = ""; if (action === "take drugs") { if (doing === "bathWithGirlFriend") { result = "尖叫,新一,你这个色狼,然后一巴掌,脸煮熟了~"; } else if (doing === "pointOutKiller") { result = "新一,这个案子就交给你的,快点找出谁是凶手吧~"; } } else { if (doing === "bathWithGirlFriend") { result = "来吧,柯南,一起洗澡吧~"; } else if (doing === "pointOutKiller") { result = "小孩子家,滚一边去!"; } } console.log(result); return arguments.callee; // 等同于return bigKenan }; console.info(bigKenan); return bigKenan; }; smallKenan("take drugs")("bathWithGirlFriend")("pointOutKiller");
#提前返回
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); }); }; } })();
#延迟计算
var averageWeight = 0; var curryWeight = function(fn) { //console.log(fn); console.warn(arguments); //就是fn var _fishWeight = []; return function() { //这部分也就是addWeight console.log(arguments); //与fn不是同一个东西 if (arguments.length === 0) { return fn.apply(null, _fishWeight); //获取参数 } else { _fishWeight = _fishWeight.concat([].slice.call(arguments)); } // 省去额外的这步addWeight() // _fishWeight = _fishWeight.concat([].slice.call(arguments)); // console.info(_fishWeight); // return fn.apply(null, _fishWeight); } }; var fishWeight = 0; //等于return的部分 var addWeight = curryWeight(function() { var i = 0; len = arguments.length; for (i; i < len; i += 1) { averageWeight += arguments[i] / len; } console.error(averageWeight); console.error(arguments); }); // addWeight(2.3); // addWeight(6.5); // addWeight(1.2); // addWeight(2.5); //可以一次传多个参数。 addWeight(2.3, 6.5, 1.2, 2.5); addWeight(); //闭包,_fishWeight不被释放 console.log(averageWeight); // 3.125 addWeight(100, 200); addWeight(); console.log(averageWeight); // 55.208333333333336
#bind的实现机制
Function.prototype.bind = function(context) { console.log(arguments); console.log(context); console.log(this); var self = this, args = Array.prototype.slice.call(arguments); return function() { console.warn(this); self.apply(context, args.slice(1)); } }; var obj = { "name": "currying", "ha": "wo" }, fun = function() { console.log(this.name); }.bind(obj); fun(); // currying // if (! function() {}.bind) { // Function.prototype.bind = function(context) { // var self = this, // args = Array.prototype.slice.call(arguments); // return function() { // return self.apply(context, args.slice(1)); // } // }; // }