本處僅僅我的存檔學習,若有侵權,請聯繫我刪除。 編程
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'
最後,這只是個腦洞!每一個語言都有自身的規律和方法論。不要真的在項目裏這麼寫,除非你的項目目的就是創造漂亮的語法。segmentfault