JSHint:不要在循环中创建函数

时间:2014-09-01 19:19:19

标签: javascript jslint jshint

在这种情况下解决JSHint错误的正确方法是什么?删除function(i)会解决吗?这样做会妨碍性能吗?

for (var i = 0; i + 1 <= pinlatlong.length; i++) {  
    (function(i) {
        setTimeout(function() {
            var latlong_array = pinlatlong[i].lat_long.split(','),
                    marker = new google.maps.Marker({
                    position: new google.maps.LatLng(latlong_array[0],latlong_array[1]),
                    map: map,
                    animation: google.maps.Animation.DROP,
                    icon: pinimage,
                    optimized: false
            });

            // info windows 
            var infowindow = new google.maps.InfoWindow({
                content: pinlatlong[i].title,
                maxWidth: 300
            });

            infoWindows.push(infowindow);

            google.maps.event.addListener(marker, 'click', (function(marker, i) {
                return function() {
                    infoWindows[i].open(map, this);
                };
            })(marker, i));

        }, i * 250); // end setTimeout
    }(i)); // end auto function
} // end for

1 个答案:

答案 0 :(得分:1)

如果删除了外部(function (i))函数,则所有setTimeouts都将使用相同的 i,因为新的i(来自函数参数)会被引入(它会lead to problems like this)。因此,通过简单地删除外部匿名函数而不改变其他代码也无法消除“提示”。 (另见How do JavaScript closures work?

虽然我一般不同意这个“提示”(以及JSLint的其他一些建议),但这里有几种不同的方法,除了仅仅禁用之外,在这种特殊情况下可以避免“提示” /忽略“提示”。


避免警告的一种方法是使用setInterval一次并仅使用一个回调函数。然后在内部回调内部进行迭代(在第i /第 - 点),并在完成时使用clearInterval。请注意,此处的目的是以“改善性能”或消除“提示”,但显示一些可能更有效或更清晰的替代方法。

function addPins (map, pinLatLong, infoWindows) {
    // In separate function so these variables are guaranteed to be
    // in a new function scope.
    var i = 0;
    var timer = setTimeout(function() {
        if (i == pinLatLng.length) {
           clearTimeout(timer);
           timer = null;
           return;
        }

        var latLng = pinLatLong[i]; // only use `i` here

        var latlong_array = latlong.lat_long.split(','),
        // If combining `var` statements, which is another hint I disagree with,
        // consider NOT using a previously introduced var's value immediately as it
        // makes it harder to see the introduction (of latlong_array in this case).
            marker = new google.maps.Marker({
                position: new google.maps.LatLng(latlong_array[0],latlong_array[1]),
                map: map,
                animation: google.maps.Animation.DROP,
                icon: pinimage,
                optimized: false
            });

        // info windows 
        var infowindow = new google.maps.InfoWindow({
            content: latlong.title,
            maxWidth: 300
        });

        infoWindows.push(infowindow);

        // Eliminated use of extra uneeded closure as all the variables
        // used are contained within the callback's function context.
        google.maps.event.addListener(marker, 'click', return function() {
           infoWindow.open(map, this);
        });

        i++;
    }, 250);
}

作为奖励,它避免了我个人在一般情况下不同意的“提示”。继续,创建数百个函数对象:JavaScript代码一直这样做。


第二种方法是使用支持setTimeout来提供它作为回调参数提供的其他参数。因此,代码也可以被修改为没有引起“提示”警告的额外function (i)。虽然这确实会产生许多超时(如原始版本)但它只使用单个函数进行回调并避免额外的闭包。

function showPin (i) {
    // Everything that was in the setTimeout callback
    // ..
}

for (var i = 0; i + 1 <= pinlatlong.length; i++) {  
    setTimeout(showPin, 250, i);
}

另一种方法是通过在另一个函数中创建闭包来进行欺骗,这有效地与原始代码做同样的事情。可以说这比原版更清晰,更容易阅读,即使不是试图消除“提示”本身。

function mkShowPin (i) {
    return function () {
        // Everything that was in the setTimeout callback
        // ..
    }
}

for (var i = 0; i + 1 <= pinlatlong.length; i++) {  
    setTimeout(mkShowPin(i), 250);
}
相关问题