gar*_*row 2 javascript php scope functional-programming
我最近尝试在javascript中使用map的实现来创建一堆项目,然后将它们应用于对象添加方法.
首先是沼泽标准的地图实现.
var map = function (fn, a)
{
for (i = 0; i < a.length; i++)
{
a[i] = fn(a[i]);
}
}
Run Code Online (Sandbox Code Playgroud)
建立.
var translateMenu = new Menu;
var languages = [ ['Chinese' , 'zh-CN']
, ['German' , 'de']
, ['French' , 'fr']
, ['Portugese' , 'pt']
, ['Hindi' , 'hi']
];
Run Code Online (Sandbox Code Playgroud)
我的功能......(不是匿名的,因为它在将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 );
Run Code Online (Sandbox Code Playgroud)
这一切都运行良好,我现在有一个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
Run Code Online (Sandbox Code Playgroud)
我通过使用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.
Run Code Online (Sandbox Code Playgroud)
无论如何,我的问题是,我如何实现map(或类似的泛型函数)来实际支持使用对象方法作为我的映射函数?.
bob*_*nce 11
试图呼叫地图(Menu.add,语言)
在这里你的问题几乎肯定是JavaScript缺乏绑定方法.
通过检查方法的获取方式,仅在呼叫时确定函数的"this"设置.如果你说其中一个:
obj.method();
obj['method']();
Run Code Online (Sandbox Code Playgroud)
JavaScript将获取对'obj'的引用,并在方法调用中设置'this = obj'.但如果你说:
obj2.method= obj.method;
obj2.method();
Run Code Online (Sandbox Code Playgroud)
现在函数内的'this'将是obj2,而不是 obj!
同样,如果从其对象中选择方法并将其作为第一类对象引用:
var method= obj.method;
method();
Run Code Online (Sandbox Code Playgroud)
将'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)
Run Code Online (Sandbox Code Playgroud)
更通用的方法是使用闭包手动绑定函数引用:
function bindMethod(fn, obj) {
return function() {
fn.apply(obj, arguments)
};
}
map(bindMethod(Menu.add, Menu), languages)
Run Code Online (Sandbox Code Playgroud)
此功能将内置到未来版本的JavaScript中:
map(Menu.add.bind(Menu), languages)
Run Code Online (Sandbox Code Playgroud)
通过写入Function.prototype.bind可以将此工具添加到当前浏览器中 - 事实上,一些JS框架已经存在.但请注意:
ECMAScript 3.1承诺你也可以将额外的参数传递给bind()来执行部分函数应用程序,这需要比上面的bindMethod()更多的代码;
当您开始在DOM对象(如事件处理程序)上保留绑定方法等引用时,IE喜欢泄漏内存.