我最近尝试在 javascript 中使用 map 的实现来创建一堆项目,然后将它们应用于对象添加方法。
首先是 map 的沼泽标准实现。
var map = function (fn, a)
{
for (i = 0; i < a.length; i++)
{
a[i] = fn(a[i]);
}
}
设置。
var translateMenu = new Menu;
var languages = [ ['Chinese' , 'zh-CN']
, ['German' , 'de']
, ['French' , 'fr']
, ['Portugese' , 'pt']
, ['Hindi' , 'hi']
];
还有我的函数......(不是匿名的,因为它后来在将 translateMenu 添加到 mainMenu 时使用。)
var langItem = function (language, subMenu)
{
return new MenuItem(language[0], 'http://translate.google.com/translate?u=www.example.com&hl=en&ie=UTF-8&tl=en&sl=' + language[1] , "" , subMenu);
}
map ( langItem , languages );
这一切都很好,我现在有一组 MenuItems 可以扔掉。
尝试调用
map( Menu.add , languages )
将导致 Menu 的内部变量未定义,并且调用失败。现在我确定这与
Menu.add()
的范围有关。方法,所以我想如果我也传入对象,它可能会起作用。我尝试创建一个可以接受对象和函数的新 map 函数,但有相同的未定义错误。
objMap (fn , obj , a) {
for (i = 0; i < a.length; i++)
{
obj.fn(a);
}
}
objMap ( add , translateMenu , languages ); // failed
我通过使用 addAll() 扩展 Menu 来解决这个问题,以获取一个数组,效果很好......
Menu.prototype.addAll = function (items){
for (i = 0; i < items.length; i++)
{
this.add(items[i]);
}
}
translateMenu.addAll( languages ); // yay! but I want a more elegant solution.
无论如何,我的问题是,我如何实现 map (或类似的通用函数)以实际支持使用对象方法作为我的映射函数? .
最佳答案
Trying to call map( Menu.add , languages )
在这里,您的问题几乎可以肯定是 JavaScript 缺少绑定(bind)方法。
函数的“this”设置仅在调用时通过检查方法的获取方式来确定。如果你说其中之一:
obj.method();
obj['method']();
JavaScript 将获取对“obj”的引用并在方法调用中设置“this=obj”。但如果你说:
obj2.method= obj.method;
obj2.method();
现在函数内的“this”将是 obj2,而不是 obj!
同样,如果您从其对象中选择方法并将其称为一等对象:
var method= obj.method;
method();
没有对象可以设置“this”,因此 JavaScript 将其设置为全局对象(对于 Web 浏览器来说也称为“窗口”)。这可能是您的情况发生的情况:“Menu.add”方法丢失了对其所有者“Menu”的所有引用,因此当它被回调时,它很可能在不知不觉中写入“window”对象的成员而不是菜单。
这对于 OO 语言来说当然是非常不寻常的,而且几乎从来都不是你想要的,但是,嘿,这就是 JavaScript 的运行方式。导致无声的、难以调试的错误都是该语言的基本原理的一部分。
要解决这个问题,您可以将对象引用传递给 map 函数,然后使用 Function.call()/apply() 正确设置“this”引用:
function mapMethod(fn, obj, sequence) {
for (var i= 0; i<sequence.length; i++)
sequence[i]= fn.call(obj, sequence[i]);
}
mapMethod(Menu.add, Menu, languages)
更通用的方法是使用闭包手动绑定(bind)函数引用:
function bindMethod(fn, obj) {
return function() {
fn.apply(obj, arguments)
};
}
map(bindMethod(Menu.add, Menu), languages)
此功能将内置到 JavaScript 的 future 版本中:
map(Menu.add.bind(Menu), languages)
并且可以通过写入 Function.prototype.bind 来将此功能添加到当前浏览器 — 确实,一些 JS 框架已经这样做了。但是请注意:
关于php - 在支持对象方法作为映射函数的javascript中实现映射?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/585840/