【问题标题】:Implement map in javascript that supports object methods as mapped functions?在支持对象方法作为映射函数的javascript中实现映射?
【发布时间】:2010-10-09 19:23:12
【问题描述】:

我最近尝试在 javascript 中使用 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() 方法的范围有关,所以我想如果我也传入对象,它可能会起作用。

我尝试创建一个可以接受对象和函数的新地图函数,但出现了同样的未定义错误。

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(或类似的通用函数)以实际支持使用对象方法作为我的映射函数?

【问题讨论】:

    标签: php javascript functional-programming scope


    【解决方案1】:

    尝试调用 map(Menu.add, 语言)

    您的问题几乎可以肯定是 JavaScript 缺少绑定方法。

    函数的“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 浏览器来说也称为“window”)。这可能是您的情况发生的情况:“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)
    

    更通用的方法是使用闭包手动绑定函数引用:

    function bindMethod(fn, obj) {
        return function() {
            fn.apply(obj, arguments)
        };
    }
    
    map(bindMethod(Menu.add, Menu), languages)
    

    此功能将内置到 JavaScript 的未来版本中:

    map(Menu.add.bind(Menu), languages)
    

    并且可以通过写入 Function.prototype.bind 来将此功能添加到当前浏览器 — 确实,一些 JS 框架已经这样做了。但请注意:

    • ECMAScript 3.1 承诺您还可以将额外的参数传递给 bind() 以执行部分​​函数应用程序,这需要比上面的 bindMethod() 更多的代码;

    • 当您开始在 DOM 对象(如事件处理程序)上留下绑定方法等引用时,IE 喜欢泄漏内存。

    【讨论】:

    • 谢谢,这是一个很棒的答案。 :D
    猜你喜欢
    • 1970-01-01
    • 2021-12-14
    • 2012-01-03
    • 2011-08-04
    • 1970-01-01
    • 1970-01-01
    • 2012-01-04
    • 1970-01-01
    • 2019-09-19
    相关资源
    最近更新 更多