js科里化
科里化定义如下: 首先将一批函数转入一个函数(然后这个函数返回一个新的函数),这中形式就叫“做科里化”(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科里化的更多相关文章
- js currying & js 科里化
js currying & js 科里化 var test = ( function (a){ console.log(`a2 =`, a);// 1 // console.log(`b2 = ...
- groovy闭包科里化参数
科里化闭包:带有预先绑定形参的闭包.在预先绑定一个形参之后,调用闭包时就不必为这个形参提供实参了.有助于去掉方法调用中的冗余重复. 使用curry方法科里化任意多个参数 使用rcurry方法科里化后面 ...
- js柯里化的一个应用
听到同学说面试一道题目 add(1)(2)(3)(4); 查询了下资料 这是一个js里面的柯里化 现象 add_curry防范返回的是一个 retVal,并不是执行结果.这里的代码很想递归,但是不是 ...
- JS 柯里化 (curry)
用 JS 理解柯里化 函数式编程风格,试图以函数作为参数传递(回调)和无副作用的返回函数(修改程序的状态). 很多语言采用了这种编程风格.JavaScript,Haskell,Clojure,Erla ...
- js 柯里化Currying
今天读一篇博客的时候,看都有关柯里化的东西,由于好奇,特意查了一下,找到一篇比较好的文章,特意收藏. 引子先来看一道小问题:有人在群里出了到一道题目:var s = sum(1)(2)(3) .... ...
- JS - 柯里化
一:what's this? 柯里化: 是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术.其实,柯里化就是用闭包原理实现函数 ...
- js柯里化
这篇文章讲的很好啊~例子很好 http://www.zhangxinxu.com/wordpress/2013/02/js-currying/ 这篇是讲函数式编程的,其中也有涉及到,说明了柯里化是一种 ...
- js 柯里化、深拷贝、浅拷贝
curry const sum = (a, b, c, d) => a + b + c + d const curry = fn => (judge = (...args) => a ...
- laravel中closure和curry 科里化函数式编程
推荐值得的一看博客文档:谢谢作者 : https://my.oschina.net/zhmsong 函数式编程curry的概念: 只传递给函数一部分参数来调用函数,然后返回一个函数去处理剩下的参数. ...
随机推荐
- 【转】C#操作Word的超详细总结
本文中用C#来操作Word,包括: 创建Word: 插入文字,选择文字,编辑文字的字号.粗细.颜色.下划线等: 设置段落的首行缩进.行距: 设置页面页边距和纸张大小: 设置页眉.页码: 插入图片,设置 ...
- GridView中给DropDownList动态绑定数据,及选择列表值后自动更新数据库
protected void sgvFile1_RowDataBound(object sender, GridViewRowEventArgs e) { DropDownList ddlAM = ( ...
- JavaScript通过preventDefault()使input[type=text]禁止输入但保留光标
一.说明 取消事件的默认动作. 该方法将通知 Web 浏览器不要执行与事件关联的默认动作(如果存在这样的动作).例如,如果 type 属性是 "submit",在事件传播的任意阶段 ...
- 解决 request.getInputStream() 只能获取一次body的问题
问题: 在使用HTTP协议实现应用间接口通信时,服务端读取客户端请求过来的数据,会用到request.getInputStream(),第一次读取的时候可以读取到数据,但是接下来的读取操作都读取不到数 ...
- 修改Linux的基本配置(修改主机名修改ip地址安装JDK/Tomcat/MySQL等等)
(一)基本操作修改 修改主机名 vi /etc/sysconfig/network NETWORKING=yes HOSTNAME=server1.itcast.cn 修改ip地址 vi /etc/s ...
- (扫盲)C#中out和ref之间的区别
首先:两者都是按地址传递的,使用后都将改变原来参数的数值. 其次:ref可以把参数的数值传递进函数,但是out是要把参数清空,就是说你无法把一个数值从out传递进去的,out进去后,参数的数值为空,所 ...
- notepad++运行python代码
notepad++运行代码 在菜单栏中点击运行或按F5,在弹出的对话框中输入下面命令 cmd /k E:\py3.6\python.exe "$(FULL_CURRENT_PATH)&quo ...
- 使用idea2016导出web项目war包
第一步配置Web Application:Exploded(已经配置的可以跳到第二步): 打开project structure(默认的快捷键是Ctrl+Alt+Shift+S),依次选择Artifa ...
- 17南宁区域赛 J - Rearrangement 【规律】
题目链接 https://nanti.jisuanke.com/t/19976 题意 给出 一个n 然后 给出 2*n 个数 可以重新排列成两行 然后 相邻的两个数 加起来 不能被三整除 可以上下相邻 ...
- iOS 几种常用的 crash log 崩溃信息调试方法
前言:crash log 对 定位崩溃问题 ,并且不容易复现,尤其是及时对appstore 上正在运营的 app 的迭代改进来说 非常重要. 1 crash两种情况 1.1 测试环境下 追踪bug 1 ...