在构建匿名函数时预先评估对象值

时间:2015-01-12 03:33:23

标签: javascript

我正在尝试为第三方控件构建一组处理程序。其中一个必需的对象是回调处理程序。问题是allProvider(item)被调用," theValue"变量不再指向同一位置 - 它始终设置为分配给它的最后一个值。我真正想要做的是评估" theValue.name"在构建数组时立即而不是以后。我现在对任何解决方案持开放态度。感谢

var handlers = [];
for(var i=0;i<myArray.length;i++){
    var theValue = myArray[i];
    handlers.push({ 
        name: myArray.name,
        allProvider: function(item){
            return "All "+ theValue.name; //This always == myArray[myArray.length - 1]
        }
    });
 }

3 个答案:

答案 0 :(得分:1)

你有一个闭包 - theValue是对父作用域变量的引用,并且在执行该函数时它指向它被分配给它的最后一个值。

You need to break the closure。一种常见的模式是使用IIFE。

allProvider: (function(theValue) {
               return function(item) {
                 return "All "+ theValue.name;
               }
             })(theValue)

答案 1 :(得分:1)

Alex是正确的,解决这个闭包问题的一种可能方法是试试这个:

var handlers = [];

myArray.forEach(function (theValue) {
    handlers.push({ 
        name: myArray.name,
        allProvider: function(item){
            return "All "+ theValue.name;
        }
    });
});

forEach方法中调用的每个匿名函数中,theValue将始终指向您所期望的内容。

编辑:我没有想到比你的更有效的东西,只是有用的东西。 map绝对是一石二鸟,可以这么说,所以你也可以试试这个:

var handlers = myArray.map(function (theValue) {
    return { 
        name: myArray.name,
        allProvider: function(item){
            return "All "+ theValue.name;
        }
    };
});

最后,如果您不想在不支持forEachmap的旧浏览器中出现可能会中断的内容,您可以尝试使用此功能:

var handlers = [],
    i;

for(i = 0; i < myArray.length; i++) {
    (function (theValue) {
        handlers.push({ 
            name: myArray.name,
            allProvider: function(item){
                return "All "+ theValue.name;
            }
        });
    }(myArray[i]));
}

答案 2 :(得分:1)

问题是在调用回调函数时,for循环已完成,因此在调用时theValue引用数组中的最后一个元素。

我建议您使用原生数组地图功能,如下所示: -

var handlers = myArray.map(function(theValue) {
    return {
        name: myArray.name,
        allProvider: function(item) {
            return "All " + theValue.name;
        }
    };
});

BTW IE8不支持地图功能。

如果你想支持IE8并且你可以做什么你可以做什么将数组中的每个元素绑定到像下面这样的函数。

var getObject = function(arrName, valueName) {
    return {
        name: arrName,
        allProvider: function(item) {
            return "All " + valueName; 
        }
    }
}

var handlers = [];
for (var i = 0; i < myArray.length; i++) {
    var theValue = myArray[i];
    handlers.push(getObject(myArray.name,theValue.name));
}