转载

开个脑洞,如何使用 javascript 实现“仿函数”(Functor)?

Functor

仿函数(Functor)是 C++ 里面一个重要的概念,简而言之就是使用重载了 operator() 运算符的对象模仿函数的行为,带来的收益是仿函数可以携带自身状态,普通的 C++ 函数不是对象,做不到这一点。

js 中的函数本身就是对象,可以携带自身状态,另外还有 curry 化等函数式编程的方法让函数缓存状态,基本上没有仿函数存在的必要。最简单的你可以这样写:

function foobar() {     return foobar.a; }  foobar.a = 1; var b = foobar(); // b=>1

这样,foobar 就携带了自身状态 a,并且可以在函数体重访问 a。

但是这里有一个问题:函数体中 foobar.a 这一句是利用闭包实现的,其中 foobar 这个引用被写死了,从效果上看 foobar 成了一个单例 。如果我想要多个 foobar 实例怎么办呢?

以及,我比较喜欢 this 指针,而不是闭包。面对这种情况,我更喜欢这样的写法:

// 伪代码  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 实现

那么怎么实现呢?我之前写了一篇文章,里面说 js 不容易实现类似的概念。但是当时我没细想,今天试了一下其实变动一下接口,还是能实现类似效果的。

基本的原理就是这样:

function f() {...} var functor = f.bind(f);

让一个函数 bind 它自己,这样它不就能用 this 访问自己了吗?但是这里还有个问题,bind 的返回结果并不是 f 自身而是另一个函数,functor 的持有者在外部访问不到 f。所以这里还要用 js 的新 api defineProperty 处理一下,使得对 functor 的某些属性访问,转移到 f 上去。

完整的实现如下:

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'

最后,这只是个脑洞!每个语言都有自身的规律和方法论。不要真的在项目里这么写,除非你的项目目的就是创造漂亮的语法。

原文  https://segmentfault.com/a/1190000006051586
正文到此结束
Loading...