函数式编程之Functional.js源码解析(一)
先简单介绍下Functional.js吧
functional.js 是模仿 Haskell 语言标准库 Prelude 制作的函数式编程库,主要实现了:
- 扩展的克里化函数
- 运算符函数化
- 紧缩的匿名函数语法
- 无须指定参数的匿名函数语法
- 函数向导语法
- 基本的通用列表操作
- 部分扩展基于对象化
其中,扩展语法由字符串表示。未能实现的特性有:
- 尾递归优化
- 模式匹配(包括参数匹配、列表匹配、情况分析)
- 惰性运算(包括无穷列表)
- 列表领悟
- 扩展绑定、同时绑定
- 其它列表操作(以及对于列表操作的基于对象化)
最近没事研究了下Function.js的源码,咱们先从to-function.js开始
to-function.js主要是让字符串变成相应的函数
第一个函数String.prototype.lambda 在下一篇文章再讨论,先来看下它的缓存机制
ps:先贴上lambda函数源码,下篇文章重点讨论
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | String.prototype.lambda = function () { var params = [], expr = this , sections = expr.ECMAsplit(/\s*->\s*/m); if (sections.length > 1) { while (sections.length) { expr = sections.pop(); params = sections.pop().split(/\s*,\s*|\s+/m); sections.length && sections.push( '(function(' +params+ '){return (' +expr+ ')})' ); } } else if (expr.match(/\b_\b/)) { params = '_' ; } else { // test whether an operator appears on the left (or right), respectively var leftSection = expr.match(/^\s*(?:[+*\/%&|\^\.=<>]|!=)/m), rightSection = expr.match(/[+\-*\/%&|\^\.=<>!]\s*$/m); if (leftSection || rightSection) { if (leftSection) { params.push( '$1' ); expr = '$1' + expr; } if (rightSection) { params.push( '$2' ); expr = expr + '$2' ; } } else { // `replace` removes symbols that are capitalized, follow '.', // precede ':', are 'this' or 'arguments'; and also the insides of // strings (by a crude test). `match` extracts the remaining // symbols. var vars = this .replace(/(?:\b[A-Z]|\.[a-zA-Z_$])[a-zA-Z_$\d]*|[a-zA-Z_$][a-zA-Z_$\d]*\s*:| 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 + ')' ); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | //cache函数String.prototype.lambda.cache = function() { var proto = String.prototype, //保留String的prototype的引用 cache = {}, //存储缓存结果缓存对象 uncached = proto.lambda, //保留没有缓存时的引用 cached = function () { var key = '#' + this ; // avoid hidden properties on Object.prototype return cache[key] || (cache[key] = uncached.call( this )); }; //cached函数用来取得缓存后的结果,如果没有进行缓存则将其加入缓存中,里边的this指向调用该函数的对象<br> cached.cached = function (){}; cached.uncache = function (){ proto.lambda = uncached }; //uncache函数用来清掉缓存 proto.lambda = cached; //重置lambda函数为缓存后的结果,下次再调用lambda时直接从缓存中读取,提高运行速度 } |
其实这里的缓存原理与懒惰函数的原理本质是一样的
var f= function (a){ var e=a*a; f.a=e; f= function (){ return "我已经缓存了" +e; } return e } alert(f(3)); alert(f(4)); //此处输出结果任然为9 |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步