在JavaScript中实现支持对象方法的映射为映射函数? [英] Implement map in javascript that supports object methods as mapped functions?

查看:124
本文介绍了在JavaScript中实现支持对象方法的映射为映射函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近我尝试在javascript中使用map实现一些项目,然后将它们应用到一个对象添加方法。



首先使用bog标准

  var map = function(fn,a)
{
for(i = 0; i< a.length; i ++)
{
a [i] = fn(a [i]);


$ / code $ / pre

$ p

  var translateMenu =新菜单; 

var languages = [['Chinese','zh-CN']
,['German','de']
,['French','fr' ]
,['葡萄牙语','pt']
,['北印度语','嗨']
];

以及我的函数...(不是匿名的,因为稍后会在将translateMenu添加到mainMenu时使用它。 )

  var langItem = function(language,subMenu)
{
return new MenuItem(language [0 ],'http://translate.google.com/translate?u=www.example.com&hl=zh-TW&ie=UTF-8&tl=en&sl='+ language [1],,subMenu );

}

map(语言,语言);

这一切都很好,我现在有一个MenuItems数组可供使用。



尝试调用 map(Menu.add,languages)会导致Menu的内部变量未定义,并且调用失败。
现在我确定这与 Menu.add()方法的范围有关,所以我想如果我传入对象作为好吧,它可能工作。



我试着创建一个新的map函数,它可以接受对象和函数,但是有相同的未定义错误。

<$对于(i = 0; i
obj.fn),pre> objMap(fn,obj,a) (一个);
}
}
objMap(add,translateMenu,languages); //失败

我用addAll()扩展Menu来取得一个数组,罚款...

pre $ Menu.prototype.addAll = function(items){
for(i = 0; i < items.length; i ++)
{
this.add(items [i]);
}
}

translateMenu.addAll(languages); // 好极了!但我想要一个更优雅的解决方案。

无论如何,我的问题是,如何实现map(或类似的通用函数)实际上支持使用对象方法作为我的映射函数吗?

解决方案


尝试调用map(Menu.add,languages)

这里你的问题几乎可以肯定是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浏览器的窗口)。这可能是你的情况发生了什么:'Menu.add'方法失去了对其所有者'Menu'的所有引用,所以当它被回调时,它很可能在不知不觉中写入'window'对象的成员而不是菜单。

这对于OO语言来说当然是非常不寻常的,几乎从来不是你想要的,但是,嘿,这就是JavaScript如何滚动。造成沉默,难以调试的错误是语言基本原理的一部分。



为了解决这个问题,你可以传递一个对象引用到你的map函数中,然后使用Function.call()/ apply()正确设置'this'引用:

 函数mapMethod(fn,obj,序列){
for(var i = 0; i< sequence.length; i ++)
sequence [i] = fn.call(obj,sequence [i]);

$ b $ mapMethod(Menu.add,Menu,languages)

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

 函数bindMethod(fn,obj){ 
return function(){
fn.apply(obj,arguments)
};


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

此功能将嵌入到未来的JavaScript版本中:

  map(Menu.add.bind(Menu ),语言)

通过写入Function.prototype,可以将此工具添加到当前浏览器.bind - 事实上,一些JS框架已经做到了。然而,注意:


  • ECMAScript 3.1承诺您还可以将额外参数传递给bind()以执行部分​​函数应用,它需要比上面的bindMethod()多一点的代码;当你开始像绑定DOM对象一样的引用时,IE喜欢泄漏内存,像事件处理程序。



I recently tried to use an implementation of map in javascript to create a bunch of items, then apply them to an objects add method.

Firstly with a bog standard implementation of map.

var map = function (fn, a)
{
    for (i = 0; i < a.length; i++)
    {
        a[i] = fn(a[i]);
    }
}

Setup.

var translateMenu = new Menu;

var languages = [ ['Chinese'   , 'zh-CN']
                , ['German'    , 'de']
                , ['French'    , 'fr']
                , ['Portugese' , 'pt']
                , ['Hindi'     , 'hi']
                ];

And my function... (not anonymous, as it's later used when adding the translateMenu to 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 );

This all worked fine, I now had an array of MenuItems to throw around.

Trying to call map( Menu.add , languages ) would result in internal variables of Menu being undefined, and the call failing.
Now I'm certain this has to do with the scope of the Menu.add() method, so i thought if I passed in the object as well, it might work.

I tried creating a new map function that would accept objects and functions, but had the same undefined error.

objMap (fn , obj , a) {
    for (i = 0; i < a.length; i++)
    {
        obj.fn(a);
    }   
}
objMap ( add , translateMenu , languages );   // failed

I worked around this by extending Menu with addAll() to take an array, which works fine...

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.

Anyway, my question is, how could I implement map (or a similar generic function) to actually support using object methods as my mapped functions?.

解决方案

Trying to call map( Menu.add , languages )

Here your problem is almost certainly that of JavaScript's lack of bound methods.

The setting of ‘this’ for a function is determined only at call-time, by examining how the method was obtained. If you say one of:

obj.method();
obj['method']();

JavaScript will pick up the reference to ‘obj’ and set ‘this= obj’ inside the method call. But if you say:

obj2.method= obj.method;
obj2.method();

Now ‘this’ inside the function will be obj2, not obj!

Similarly, if you pick the method off its object and refer to it as a first-class object:

var method= obj.method;
method();

There will be no object for ‘this’ to get set to, so JavaScript sets it to the global object (aka ‘window’ for web browsers). This is probably what is happening in your case: the ‘Menu.add’ method loses all reference to its owner ‘Menu’, so when it gets called back it is most likely unknowingly writing to members of the ‘window’ object instead of a menu.

This is of course highly unusual for an OO language, and almost never what you want, but hey, that's how JavaScript rolls. Causing silent, hard-to-debug errors is all part of the language's rationale.

To get around this problem you could pass an object reference in to your map function, then use Function.call()/apply() to set the ‘this’ reference correctly:

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)

A more general way would be to bind function references manually, using a closure:

function bindMethod(fn, obj) {
    return function() {
        fn.apply(obj, arguments)
    };
}

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

This capability will be built into a future version of JavaScript:

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

And it is possible to add this facility to current browsers by writing to Function.prototype.bind — indeed, some JS frameworks do already. However note:

  • ECMAScript 3.1 promises you'll also be able to pass extra arguments into bind() to do partial function application, which requires a little more code than bindMethod() above;

  • IE loves to leak memory when you start leaving references like bound methods on DOM objects like event handlers.

这篇关于在JavaScript中实现支持对象方法的映射为映射函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆