网站: JavaEye 作者: Lich_Ray 发表时间: 2007-07-26 22:17 此文章来自于 http://www.iteye.com
声明:本文系JavaEye网站原创文章,未经JavaEye网站或者作者本人书面许可,任何其他网站严禁擅自发表本文,否则必将追究法律责任!
原文链接: http://www.iteye.com/topic/105854
引用
本文对刚刚在网络上现身的 JavaScript 函数式编程库
functional.js 进行详尽的解读(地址已更正,感谢 hax)。
functional.js 是模仿 Haskell 语言标准库 Prelude 制作的函数式编程库,主要实现了:
其中,扩展语法由字符串表示。未能实现的特性有:
下面我们一边分析源代码,一边讲解库的用法。 一、库安装和概览
下面是安装函数 Functional.install 的源代码(中文注释为笔者所加,下同):
代码
Functional.install = function(except) { // except 参数是一个对象,不加载这些操作 var source = Functional, target = window; // 复制操作到全局环境 window,仅限于浏览器环境 for (var name in source) name == 'install' // 当然,不能把 install 复制到 source || name.charAt(0) == '_' // 命名开头为 _,私有属性 || except && name in except || {}[name] // work around Prototype || (target[name] = source[name]); }
一般只要执行 Functional.install() 一句即可。 二、高阶函数操作 以上两个操作亦可见于 Function.prototype,用法:'1+'.lambda().sequence('2*')(2) ==> 6 3. Function.prototype.flip ()
以上操作的介绍网上到处都是,不再赘述;但有一点不同,即它们除了接受正常参数之外,还在最后接受一个可选参数 object::Object,它被用于指定操作执行的对象/环境。 另外,这些操作全部基于命令式风格实现,对于没有尾递归优化的 JavaScript 来说,效率有保障。 四、群体谓词操作 五、函数扩展
代码
Function.prototype.curry = function(/*args...*/) { var fn = this; var args = [].slice.call(arguments, 0); return function() { return fn.apply(this, args.concat([].slice.call(arguments, 0))); }; }
返回那个传说中的可在参数不足时分步调用的函数——Currying 算子。 形式:f.curry(args1...)(args2...) == f(args1..., args2...) 其它的 curry 类函数有:
3. Function.prototype.partial ([]) 六、工具函数
代码
Functional.until = function(pred, fn) { // 使用时参数会被强制转为 Functional 的函数,参数可为字符串 fn = Function.toFunction(fn); pred = Function.toFunction(pred); // 返回一个接受一个参数的函数, return function(value) { // 它不断对此参数 apply 函数 pred, while (!pred.call(null, value)) // 并用 fn(value) 的值更新 value, value = fn.call(null, value); return value; // 直到测试结果为 true。 } }
类似 Haskell 的 until,是一种函数式的循环,用命令式风格实现。 4. Functional.zip ([]) 特别注意,此 zip 并非 Haskell 中的 zip,它接受可变参数列表而不是列表的列表。 形式:zip(a, b...) == [[a0, b0], [a1, b1], ...] 以上的章节中绑定在 Functional 上函数都可作为 Function 的对象方法直接使用,我们看这一行:
代码
Functional.__initalFunctionState = Functional._startRecordingMethodChanges(Function.prototype);
前文对它们作出了定义,这里忽略。用法:name(arg, args...) == arg.name(args...)。 七、语法扩展
代码
String.prototype.lambda = function() { var params = []; // 存储字符串形式的参数的列表 var expr = this; // ECMAsplit 是作者为兼容 IE6.0 所写的 split 版本 var sections = expr.ECMAsplit(/\s*->\s*/m); // 使字符串被 '->' 分割 /* 注意,分割的结果支持超过任意个 '->',下面会发现, -> 9 或者 x -> y -> x+y 这样的代码也会被正确理解。 */ if (sections.length > 1) { // 这就是所谓的“正确理解”了 while (sections.length) { expr = sections.pop(); // 然后把参数打碎,再重组为 JS 可识别的参数语法 /* 也就是说,x y -> x*y+2 和 x,y -> x*y+2 都可被接受。 */ params = sections.pop().split(/\s*,\s*|\s+/m); // 装配成代码,顺便支持尾递归语法 sections.length && sections.push('(function('+params+'){return ('+expr+')})'); } } else if (expr.match(/\b_\b/)) { params = '_'; // 忽略参数的前奏,下文判断 } else { // 这里处理运算符表达式参数缺失的情况,相当于运算符函数化 // 分为前缺失和后缺失两种情况, var leftSection = expr.match(/^\s*(?:[+*\/%&|\^\.=<>]|!=)/m); var rightSection = expr.match(/[+\-*\/%&|\^\.=<>!]\s*$/m); /* 注意,前缺失类似 *2,后缺失类似 2*,复杂表达式同样支持 此外,前后都缺失也可以,比如 * 甚至是 *3* */ if (leftSection || rightSection) { // 翻译缺失代码的技术:用 $1、$2 代换参数 if (leftSection) { params.push('$1'); expr = '$1' + expr; } if (rightSection) { params.push('$2'); expr = expr + '$2'; } } else { // 这个地方就有点意思了;它使得函数支持参数指定缺失 /* 比如 x*y 就已经是一个函数了,相当于 x y->x*y 作者还特别防止了一个 bug,即对象属性访问语法中, 属性部分不被认为是未指定的参数。例如 obj.pro + 4 这个函数,只有 obj 一个参数 而且,this 和 arguments 不会被认为是未知数。 */ var vars = this.replace(/(?:\b[A-Z]|\.[a-zA-Z_$])[a-zA-Z_$\d]*|[a-zA-Z_$][a-zA-Z_$\d]*:|this|arguments|'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"/g, '') .match(/([a-z_$][a-z_$\d]*)/gi) || []; for (var i = 0, v; v = vars[i++]; ) params.indexOf(v) >= 0 || params.push(v); } } return new Function(params, 'return (' + expr + ')'); // 把代码装配成函数对象 }
八、过滤器生成器 九、其它用户级函数 2. Functional.constfn = Functional.K = function(x) {return function() {return x}}; 3. .toFunction () 十、结语 |
《 functional.js 介绍及源码分析 》 的评论也很精彩,欢迎您也添加评论。查看详细 >>
推荐相关文章:
javascript中的FP
Programming in Emacs Lisp笔记(十八) 终结
JavaEye推荐
上海乐福狗信息技术有限公司:诚聘技术经理和开发工程师
免费下载IBM社区版软件--它基于开放的标准,支持广泛的开发类型,让您的开发高效自主!
京沪穗蓉四地免费注册,SOA技术高手汇聚交锋.
上海:优秀公司德比:高薪诚聘 资深Java工程师
广州:优易公司:诚聘Java工程师,开发经理
上海:尤恩斯国际集团:诚聘开发工程师
北京:优秀公司NHNChina招聘:WEB开发,系统管理,JAVA开发, DBA