php - 在支持对象方法作为映射函数的javascript中实现映射?

标签 php javascript functional-programming scope

我最近尝试在 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 框架已经这样做了。但是请注意:
  • ECMAScript 3.1 promise 您还可以将额外的参数传递给 bind() 以执行部分​​函数应用程序,这比上面的 bindMethod() 需要更多的代码;
  • 当您开始在 DOM 对象(如事件处理程序)上留下绑定(bind)方法等引用时,IE 喜欢泄漏内存。
  • 关于php - 在支持对象方法作为映射函数的javascript中实现映射?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/585840/

    相关文章:

    php - 将 php 数组插入 mySql

    php - 在 php 脚本中创建数据库表的克隆

    php - 如何在 php 中对每个其他字符进行 CAPITaLiZe?

    Haskell疑问: how to transform a Matrix represented as: [String] to a Matrix Represented as [[Int]]?

    php - 这是 mysql/php 正确删除一行吗?

    没有 Jquery 和 CSS3 的 Javascript 淡入淡出

    javascript - 将 ES6 模块与 WebPack 一起使用,为什么还需要 require

    javascript - 从字符串名称到 id 的过滤对象数组

    functional-programming - or-like feature in case … of statement?或者更通用的模式?

    c# - 有没有办法用 C# 中的给定比较函数在功能上比较两个已知大小相等的列表?