我想为其参数创建一个函数映射。此地图将动态更新。最后,将使用相应的参数调用所有函数。
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.
我尝试了两种方法:
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] }
这里我存储对函数的引用而不是整个函数定义。但我必须遍历整个数组才能添加更多参数。
有没有更好的方法来维护这张地图?上述方法有哪些缺点?
更新
回答“在什么情况下我需要这个”的问题:
我正在维护从参数到函数的映射。我动态更新它。 稍后在我的代码中,我想创建一个反向映射并使用其所有参数调用函数。
例如:
1 -> foo1
2 -> foo2
3 -> foo1,foo2
4 -> foo1
... and so on.
然后我想创建一个这样的反向地图:
foo1 -> [1,3,4...]
foo2 -> [2,3,...]
最后致电:
foo1( [1,3,4...])
foo2( [2,3,...])
答案 0 :(得分:3)
JavaScript中的对象只能将字符串作为键,因此使用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);
}
答案 1 :(得分:2)
为了使用对象(或函数)作为键,您需要使用Harmony(EcmaScript 6)WeakMap
或Map
。它们目前都是实验性的,都可以在Firefox中使用。我相信Chrome中也可以使用WeakMap
(使用正确的标记设置?)。
如果您的平台支持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
答案 2 :(得分:2)
除非有将对象作为键的本机跨浏览器解决方案,否则您始终可以实现自己的解决方案。这是你可以做的一个例子。在下面的代码中,ObjectMap
会将生成的密钥存储为需要作为property
的{{1}}的{{1}}。用于在object
上存储key
的{{1}}名称会随机化,以减少可能的冲突。然后,地图实现可以使用此property
的{{1}}来检索key
上的object
,然后检索其关联的property
。
JSPERF:http://jsperf.com/object-map
value
答案 3 :(得分:1)
致Dagg Nabbit在我的问题评论中提出这一建议。
“不要忘记功能可以有属性。你可以随时存储 函数在一个数组中,并将它们的索引附加到数组中 作为一个属性,并以这种方式看待它们。“ - Dagg Nabbit
考虑以下 args-to-callback 参数的映射:
地图:
1 -> foo1
2 -> foo1,foo2
3 -> foo2
目标是构建一个 callback-to-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建议)
干杯!