科里化定义如下: 首先将一批函数转入一个函数(然后这个函数返回一个新的函数),这中形式就叫“做科里化”(currying)

Function.prototype.curry = function(){
var fn = this, // 这里就是在预装参数,将参数抓住,缓存在变量args中
args = Array.prototype.slice.call(arguments);
return function(){
return fn.apply(this, args.concat(
Array.prototype.slice.call(arguments)))
};
}; String.prototype.csv = String.prototype.split.curry(/,\s*/);
var results = ("Mugan, Jin, Fuu").csv(); console.log(results[0],results[1],results[2]);

上面这个例子看懂了吗?

curry这个函数做的事情,是将函数中的this和arguments缓存在了闭包之中。

当split函数调用curry的时候,curry中的this就是split函数本身, 正则表达式这个参数则是预存在curyry中的arguments。

虽然这段代码实现已经很不错了,但是我们还可以进行一些改进。 上面这个curry函数,实现了将所有参数缓存在闭包之中。 当调用闭包返回的新的函数的时候才去处理之前预装的所有参数。

但是如果我不想让所有的参数全部预装,而是只预装其中一部分, 另外一部分参数要在调用闭包返回的那个新的函数中,将这部分参数传入。

Function.prototype.partial = function(){
var fn = this, args = Array.prototype.slice.call(arguments);
return function(){
var arg = 0;
for (var i = 0; i < args.length && arg < arguments.length; i++){
if (args[i] === undefined){
args[i] = arguments[arg++];
}
}
return fn.apply(this, args);
};
}; var delay = setTimeout.partial(undefined, 10);
delay(function(){
alert(true);
}); var bindClick = document.body.addEventListener.partial("click", undefined, false);
bindClick(function(){
alert(true);
});

partial()的实现和curry()有些相像。 在第一批的参数中,我们用undefined代表了那部分缺省参数。 在后面delay调用的时候,才将真正想要被处理的参数传递进去。

再来看一道面试题:

var fn = function(a,b,c){
    return a+b+c;
}

需要写一个函数,满足curry(fn)(1)(2)(3) //6

var curry = function(fn){
//参数集合
var args = [];
//函数的形参个数
var fnLen = fn.length; return function(){
//合并参数
args = args.concat([].slice.call(arguments));
//返回函数自身
if(args.length < fnLen) return arguments.callee;
//执行函数并返回结果
return fn.apply(this,args);
};
}; var fn=function(a,b,c){
return a+b+c;
}; var c = curry(fn)(1)(2)(3);
alert(c); //

用AOP装饰函数

首先给出Function.prototype.before方法和Function.prototype.after方法:

Function.prototype.before = function(beforefn){
var _self = this; //保存原函数的引用
return function(){ //返回包含了原函数和新函数的“代理”函数
beforefn.apply(this,arguments); //执行新函数,且保证this不被劫持,新函数接受的参数
//也会被原封不动地传入原函数,新函数在原函数之前执行
return _self.apply(this,arguments); //执行原函数并返回原函数的执行结果,并且保证this不被劫持
}
};
Function.prototype.after = function(afterfn){
var _self = this;
return function(){
var ret = _self.apply(this,arguments);
afterfn.apply(this,arguments);
return ret;
}
};

Function.prototype.before接受一个函数当作参数,这个函数即为新添加的函数,它装载了新添加的功能代码。

接下
来把当前的this保存起来,这个this指向原函数,然后返回一个“代理”函数,这个“代理”函数只是结构上像代理而已,并不承担代理的职责(比如控制
对象的访问等)。它的工作是把请求分别转发给新添加的函数和原函数,且负责保证它们的执行顺序,让新添加的函数在原函数之前执行(前置装饰),这样就实现
了动态装饰的效果。

我们注意到,通过Function.prototype.after的原理跟Function.prototype.before一模一样,唯一不同的地方在于让新添加的函数在原函数执行之后再执行。

用Function.prototype.before来增加新的window.onload事件是多么简单:

window.onload = function(){
console.log(1);
} window.onload = (window.onload || function(){}).after(function(){
console.log(2);
}).after(function(){
console.log(3);
}).after(function(){
console.log(4);
});

js科里化的更多相关文章

  1. js currying & js 科里化

    js currying & js 科里化 var test = ( function (a){ console.log(`a2 =`, a);// 1 // console.log(`b2 = ...

  2. groovy闭包科里化参数

    科里化闭包:带有预先绑定形参的闭包.在预先绑定一个形参之后,调用闭包时就不必为这个形参提供实参了.有助于去掉方法调用中的冗余重复. 使用curry方法科里化任意多个参数 使用rcurry方法科里化后面 ...

  3. js柯里化的一个应用

    听到同学说面试一道题目 add(1)(2)(3)(4); 查询了下资料  这是一个js里面的柯里化 现象 add_curry防范返回的是一个 retVal,并不是执行结果.这里的代码很想递归,但是不是 ...

  4. JS 柯里化 (curry)

    用 JS 理解柯里化 函数式编程风格,试图以函数作为参数传递(回调)和无副作用的返回函数(修改程序的状态). 很多语言采用了这种编程风格.JavaScript,Haskell,Clojure,Erla ...

  5. js 柯里化Currying

    今天读一篇博客的时候,看都有关柯里化的东西,由于好奇,特意查了一下,找到一篇比较好的文章,特意收藏. 引子先来看一道小问题:有人在群里出了到一道题目:var s = sum(1)(2)(3) .... ...

  6. JS - 柯里化

    一:what's this? 柯里化: 是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术.其实,柯里化就是用闭包原理实现函数 ...

  7. js柯里化

    这篇文章讲的很好啊~例子很好 http://www.zhangxinxu.com/wordpress/2013/02/js-currying/ 这篇是讲函数式编程的,其中也有涉及到,说明了柯里化是一种 ...

  8. js 柯里化、深拷贝、浅拷贝

    curry const sum = (a, b, c, d) => a + b + c + d const curry = fn => (judge = (...args) => a ...

  9. laravel中closure和curry 科里化函数式编程

    推荐值得的一看博客文档:谢谢作者  : https://my.oschina.net/zhmsong 函数式编程curry的概念: 只传递给函数一部分参数来调用函数,然后返回一个函数去处理剩下的参数. ...

随机推荐

  1. SQL查询父节点下的所有子节点(包括子节点下的子节点,无限子节点)

    -->Title:Generating test data -->Author:wufeng4552 -->Date :2009-09-30 08:52:38 set nocount ...

  2. PowerPC架构与X86架构

    PowerPC架构 PowerPC是一种精简指令集(RISC)架构的中央处理器(CPU),其基本的设计源自IBM(国际商用机器公司)的POWER(Performance Optimized With ...

  3. 检查arg是方法还是函数?

    from types import MethodType,FunctionType def check(arg): """ 检查arg是方法还是函数? :param ar ...

  4. 标准c内存函数的使用方法

    标准c内存函数 calloc 语法:     #include <stdlib.h>   void *calloc( size_t num, size_t size ); 功能: 函数返回 ...

  5. JAVA中遍历Map和Set方法,取出map中所有的key

    Java遍历Set集合 1.迭代器遍历: Set<String> set = new HashSet<String>(); Iterator<String> it ...

  6. 在运行myeclipse10注册机时,显示找不到com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel这个包

    在win7下安装MyEclipse10.安装完成之后运行注册机,总是提示classnotfond显示找不到com.sun.java.swing.plaf.nimbus.NimbusLookAndFee ...

  7. json教程系列(4)-optXXX方法的使用

    在JSONObject获取value有多种方法,如果key不存在的话,这些方法无一例外的都会抛出异常.如果在线环境抛出异常,就会使出现error页面,影响用户体验,针对这种情况最好是使用optXXX方 ...

  8. $ListView的优化机制和滑动时数据错乱的讨论

    Refer:http://www.myexception.cn/mobile/1612364.html (一)Android ListView的基本用法 1.创建一个实体类Person,为其添加Get ...

  9. arcgis for flex map遮罩

    效果1:map的遮罩(对整个map进行遮罩) 效果2:对某个图层进行遮罩

  10. 跨平台移动开发_PhoneGap API Camera 使用摄像头采集照片.

    camera对象提供对设备默认摄像头应用程序的访问. 程序运行效果 相关代码 <!DOCTYPE html> <html> <head> <title> ...