仿函数(Functor)是 C++ 里面一个重要的概念,简而言之就是使用重载了 operator() 运算符的对象模仿函数的行为,带来的收益是仿函数能够携带自身状态,普通的 C++ 函数不是对象,作不到这一点。编程
js 中的函数自己就是对象,能够携带自身状态,另外还有 curry 化等函数式编程的方法让函数缓存状态,基本上没有仿函数存在的必要。最简单的你能够这样写:api
function foobar() { return foobar.a; } foobar.a = 1; var b = foobar(); // b=>1
这样,foobar 就携带了自身状态 a,而且能够在函数体重访问 a。缓存
可是这里有一个问题:函数体中 foobar.a 这一句是利用闭包实现的,其中 foobar 这个引用被写死了,从效果上看 foobar 成了一个单例。若是我想要多个 foobar 实例怎么办呢?闭包
以及,我比较喜欢 this 指针,而不是闭包。面对这种状况,我更喜欢这样的写法:app
// 伪代码 function foobar() { return this.b; } foobar.setB = function (val) { this.b = val } var foo = new foobar; foo.setB(1); var b = foo(); // b=>1
那么怎么实现呢?我以前写了一篇文章,里面说 js 不容易实现相似的概念。可是当时我没细想,今天试了一下其实变更一下接口,仍是能实现相似效果的。函数式编程
基本的原理就是这样:函数
function f() {...} var functor = f.bind(f);
让一个函数 bind 它本身,这样它不就能用 this 访问本身了吗?可是这里还有个问题,bind 的返回结果并非 f 自身而是另外一个函数,functor 的持有者在外部访问不到 f。因此这里还要用 js 的新 api defineProperty 处理一下,使得对 functor 的某些属性访问,转移到 f 上去。this
完整的实现以下:prototype
function makeFunctor(fn, props) { function thisFn() { return fn.apply(this, Array.prototype.slice.call(arguments)); } var ret = thisFn.bind(thisFn); for (var key in props) { if (!props.hasOwnProperty(key)) { continue; } Object.defineProperty(ret, key, { configurable : true, enumerable : true, get : function () { return thisFn[key]; }, set : function (value) { thisFn[key] = value; } }); ret[key] = props[key]; } return ret; }
经过 makeFunctor,咱们能够经过一个函数 fn 建立不少个 functor,每个都有自身的状态,互不影响。而且在 fn 中咱们可使用 this 访问自身状态。好比:指针
function hello () { alert('Hello, ' + this.name); } hello.create = function () { makeFunctor(hello, { name : 'Tom' }); } var ftHello = hello.create(); var ftHello2 = hello.create(); ftHello(); // Hello, Tom' ftHello.name = 'Jack'; ftHello(); // Hello, Jack' ftHello2(); // Hello, Tom'
最后,这只是个脑洞!每一个语言都有自身的规律和方法论。不要真的在项目里这么写,除非你的项目目的就是创造漂亮的语法。