2013-04-27 60 views
2

我想爲它的參數創建一個函數映射。這張地圖會動態更新。最後所有的函數都會被調用,並有相應的參數。什麼是創建函數映射到參數的最有效方法?

function foo1(x) { 
    //do something with x 
} 

function foo2(x) { 
    //do something else with x 
} 

var map = {}; 
map[foo1] = [1,2,3]; //this array is updated dynamically in my code 
map[foo2] = [4,5,6]; 

// I want to call foo1 and foo2 with their [1,2,3] and [4,5,6] arguments respectively. 

我試圖2點的方法:

  • 轉換foo1到字符串(使用toString()法)作爲用於地圖的關鍵。然後稍後我使用Function構造函數從這個字符串中取回函數。但是,如果這會影響表演,我恐怕是這樣。
// This works. But concerned about the performance 

map[foo1.toString()] = [1,2,3]; 

for(i in map){ 
    var fn = Function('return '+ i)(); 
    fn(map[i]); 
} 
  • 存儲對象是包的功能和它們對應的參數,如:
{ fn : foo1 , args : [1,2,3] } 
    { fn : foo2 , args : [4,5,6] } 

我在這裏存儲的功能,而不是整個函數定義的引用。但我必須遍歷整個數組以添加更多參數。

有沒有更好的方法來維護這張地圖?上述方法有什麼缺點?

UPDATE

回答這個問題:「在什麼情況下,我需要這個」:

我保持距離參數的地圖功能。我動態更新它。 後來在我的代碼中,我想創建一個反向映射並用其所有參數調用函數。

對於如:

1 -> foo1 
2 -> foo2 
3 -> foo1,foo2 
4 -> foo1 
... and so on. 

然後我想創建反向映射是這樣的:

foo1 -> [1,3,4...] 
foo2 -> [2,3,...] 

最後呼籲:在JavaScript

foo1([1,3,4...]) 

foo2([2,3,...]) 
+0

你的總體目標是什麼?我想不出一個會要求這樣的事情的情況。 – 2013-04-27 02:50:22

+2

不要忘記函數可以有屬性。您可以將函數始終存儲在數組中,並將它們的索引作爲索引附加到函數中,然後以這種方式查找它們。 – 2013-04-27 03:42:34

+0

@DaggNabbit,這基本上是我發佈的解決方案的一個變種;) – plalx 2013-04-27 04:03:00

回答

2

除非有本地跨瀏覽器解決方案將對象作爲關鍵字,否則您始終可以實現自己的解決方案。以下是你可以做的一個例子。在下面的代碼中,ObjectMap會將生成的密鑰存儲爲objectproperty,該密鑰需要充當key。用於在object上存儲keyproperty名稱被隨機化以減少可能的衝突。然後地圖實現可以使用此propertyvalue檢索object上的key,然後檢索它的關聯value

JSPERF:http://jsperf.com/object-map

function ObjectMap() { 
    this.key = 0; 
    //you should implement a better unique id algorithm 
    this.mapId = '_' + Math.floor(Math.random() * 10000); 
    this.data = {}; 
} 

ObjectMap.prototype = { 
    set: function (object, value) { 
     var key = ++this.key; 

     if (object[this.mapId]) { 
      return; 
     } 

     object[this.mapId] = key; 
     this.data[key] = value; 
    }, 

    get: function (object) { 
     var key = object[this.mapId]; 

     return key? this.data[key] : null; 
    }, 

    remove: function (object) { 
     var key = object[this.mapId]; 
     if (!key) { 
      return; 
     } 
     delete this.data[key]; 
     delete object[key]; 
    } 
}; 

function a() {} 

var map = new ObjectMap(); 

map.set(a, 'test'); 

console.log(map.get(a)); //test 
+0

+1非常好的示例。 – FacePalm 2013-04-27 08:04:44

3

對象只能有一個字符串作爲密鑰,所以使用map[foo1]幾乎與map[foo1.toString()]相同。這些都有,你有沒有注意到的問題:他們拋棄封閉過的變量,例如:

function makeCounter() { 
    var counter = 0; 
    return function() { return ++counter; } 
} 

如果我有

var myCounter = makeCounter(); 

然後myCounter.toString()function() { return ++counter; },並試圖去重構一個與構造函數Function將導致錯誤的counter參考。

真的,最好的選擇可能是使用該功能的名稱屬性和數值,使用對象喜歡你的建議:

var map = {}; 
map['foo1'] = { fn: foo1, args: [1, 2, 3] }; 

然後,如果你想在以後添加更多的參數,它的很明顯:

map['foo1'].args.push(4); 

,並呼籲所有這些,你可能會使用這樣的:

for(var functionName in map) { 
    if(!Object.prototype.hasOwnProperty.call(map, functionName)) { 
     continue; 
    } 
    map[functionName].fn.apply(null, map[functionName].args); 
} 
+0

如果來自不同範圍的兩個函數具有相同的名稱,是否會有衝突? – FacePalm 2013-04-27 03:06:34

+0

@FacePalm:是的,不幸的。如果這是不可接受的,你將不得不使用你的解決方案與對象數組。 – icktoofay 2013-04-27 03:07:18

2

爲了使用對象(或函數)作爲鍵,您需要使用Harmony(EcmaScript 6)WeakMapMap。它們都是實驗性的,都可以在Firefox中使用。我相信WeakMap也可能在Chrome中提供(具有正確的標誌設置?)。

如果你的平臺支持WeakMap,並選擇將其納入,那麼它們的用法非常簡單:

var myWeakMap=new WeakMap(); 
myWeakMap.get(key [, defaultValue]); 
myWeakMap.set(key, value); 
myWeakMap.has(key); 
myWeakMap.delete(key); 
myWeakMap.clear(); 

的更多信息(注意MDN引用出現不公開):

另外:您也可以使用一個函數數組,然後使用indexOf獲取該函數的索引,然後使用該索引訪問另一個數組中的參數。

function a(){} 
function b(){} 
var x=[a,b].indexOf(b); //x=1 
+0

+1爲您的第二種方法。符合我的要求。 – FacePalm 2013-04-27 09:26:50

1

貸Dagg Nabbit於下我的問題的評論暗示這一點。

「不要忘記功能可以有屬性。你總是可以在存儲陣列中的 功能,並附上自己的指數陣列到 功能的屬性格式中,並看看他們的方式。「 - Dagg Nabbit

考慮的ARGS到回調參數如下圖:

地圖:

1 -> foo1 
2 -> foo1,foo2 
3 -> foo2 

的目標是建立一個回調到ARGS地圖(反向地圖)是這樣的:

callbackMap:

foo1 -> [1,2] 
foo2 -> [2,3] 

方法:

var allArgsPossible = [1,2,3] 

// contains the list of callbacks to be called 
var callbackArray = []; 

//maps the callback index in callbackArray to the callback's arguments 
//callbackMap[index] = args means callbackArray[index] will be called with parameter "args" 
var callbackMap = {}; 

for(i in allArgsPossible) 
{ 
    var item = allArgsPossible[i]; 
    var callbacks = map[ item ]; 
    for(j in callbacks) 
    { 
     var callback = callbacks[j]; 

     if(callback.index == undefined) 
     { 
      var index = callbackArray.length; 
      // adding a new property "index" to the callback 
      callback.index = index; 
      callbackMap[index] = [item]; 
      //create a new entry in callbackArray 
      callbackArray.push(callback); 
     } 
     else 
     { 
      callbackMap[callback.index].push(item); 
     } 
    } 
} 

console.log(JSON.stringify(callbackMap)); 

for(i in callbackArray) 
{ 
    var callback = callbackArray[i]; 
    //get arguments from our reverse map 
    var args = callbackMap[callback.index]; 
    // Bingo ! 
    callback(args); 
} 

你可以得到整個圖片瀏覽:http://jsfiddle.net/kyvUA/2/

一點這裏要注意的是,回調函數可能已經有一個「指數」屬性其他一些目的。如果這是一個問題,您可以生成一個隨機字符串,並將該屬性存儲在回調中,並將索引作爲值。 (如@plalx所示)

乾杯!

相關問題