JS提示:Don't在循环中生成函数

JSHint: Don't make functions within a loop

本文关键字:循环 函数 提示 Don JS      更新时间:2023-09-26

在这种情况下,解决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

如果外部(function (i))函数被删除,那么所有setTimeouts都将使用相同的i,因为(函数参数中的)新i将不会被引入(这将导致类似的问题)。因此,在不更改其他代码的情况下,不能通过简单地从外部匿名函数中删除"提示"来消除它。(另请参阅JavaScript闭包是如何工作的?)

虽然我通常不同意这个"提示"(以及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);
}