2016-02-27 56 views
1

標準Function.prototype.bind方法在每次調用時創建一個新函數。 我需要存儲某處並重用該函數的有界變體。Javascript:重用有界功能

這不是火箭科學來實現功能bindArg它適用於對象參數

const fnStorage = new WeakMap(); 
function bindArg(fn, arg) { 
    if (!fnStorage.has(fn)) { 
    fnStorage.set(fn, new WeakMap()); 
    } 
    if (!fnStorage.get(fn).has(arg)) { 
    fnStorage.get(fn).set(arg, fn.bind(null, arg)); 
    } 
    return fnStorage.get(fn).get(arg); 
} 

這個解決方案能正常工作,但僅限於對象參數。可以通過將WeakMap更改爲Map來完成標量參數。但是這並不好,因爲Map將繼續引用函數的有限變體並防止垃圾收集。

有什麼辦法可以實現bindArg函數,它是純粹的不可變的,沒有任何類型的參數泄漏內存?

+0

我假設你試圖記憶綁定函數以避免'Function.prototype.bind'具有「壞」性能的聲譽? – naomik

+0

不,這是爲了簡化平等檢查 –

+0

這聽起來像一個[XY問題](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)。你實際上在做什麼代碼? – naomik

回答

2

您可以使用原始數據類型爲對象MapWeakMap

function isPrimitive(value) { 
    return Object(value) !== value; 
} 

var primStore = new Map; 
var objStore = new WeakMap; 

function bindArg(fn, arg) { 
    var store = isPrimitive(arg) ? primStore : objStore; 
    if (!store.has(arg)) store.set(arg, new WeakMap); 
    if (!store.get(arg).has(fn)) store.get(arg).set(fn, fn.bind(null, arg)); 
    return store.get(arg).get(fn); 
} 

請注意,我們返回store.get(arg).get(fn)而不是store.get(fn).get(arg)。這個翻轉對bindArg函數的實際語義沒有任何影響,但是當我們要區分基本數據類型和對象時,這是必要的。


編輯:或者,你可以在一個WeakMap創建存儲在Map和對象的原始值的新WeakMap2數據結構如下:

var WeakMap2 = defclass({ 
    constructor: function() { 
     this.map1 = new Map; 
     this.map2 = new WeakMap; 

     if (arguments.length > 0) { 
      for (var object in argument[0]) { 
       if (isPrimitive(object)) 
        throw new TypeError("Iterator value " + 
         object + " is not an entry object"); 
       else this.set(object[0], object[1]); 
      } 
     } 
    }, 
    get: function (key) { 
     return (isPrimitive(key) ? this.map1 : this.map2).get(key); 
    }, 
    set: function (key, value) { 
     return (isPrimitive(key) ? this.map1 : this.map2).set(key, value); 
    }, 
    has: function (key) { 
     return (isPrimitive(key) ? this.map1 : this.map2).has(key); 
    }, 
    delete: function (key) { 
     return (isPrimitive(key) ? this.map1 : this.map2).delete(key); 
    } 
}); 

function defclass(prototype) { 
    var constructor = prototype.constructor; 
    constructor.prototype = prototype; 
    return constructor; 
} 

function isPrimitive(value) { 
    return Object(value) !== value; 
} 

不過,我不會推薦因爲它增加了一層抽象,使你的代碼變慢。