不要在循环中创建函数

时间:2022-08-17 20:03:36

What would be the correct way to solve the JSHint error in this case? Would removing function(i) solve it? And does having it this way hinder performance?

在这种情况下,解决JSHint错误的正确方法是什么?移除函数(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 个解决方案

#1


1  

If the outer (function (i)) function was removed then all the setTimeouts would use the same i because a new i (from the function parameter) would not be introduced (and it would lead to problems like this). As such the "hint" cannot be eliminated by simply removing it the outer anonymous function without changing other code as well. (Also see How do JavaScript closures work?)

如果删除了外部(函数(i)))函数,那么所有的setTimeouts都将使用相同的i,因为不会引入新的i(来自函数参数)(这将导致类似的问题)。因此,不能通过简单地删除外部匿名函数而不更改其他代码来消除“提示”。(还可以看到JavaScript闭包是如何工作的?)

While I disagree with this "hint" in general (and several other recommendations JSLint has), here are several different methods in which the "hint" can be avoided in this particular case besides merely disabling/ignoring the "hint".

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


One way to avoid the warning is to use setInterval once and using only a single callback function. The iteration (over i'th/the-point) is then advanced inside the callback inside and clearInterval is used when done. Note that the intent here is not to "improve performance" or eliminate the "hint" but show an alternative approach that some may perfer or find cleaner.

避免警告的一种方法是使用setInterval一次,并且只使用一个回调函数。然后迭代(在i'th/ The -point上)在回调内部进行,完成时使用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);
}

As a bonus it avoids the "hint" which I personally disagree with in general cases. Go ahead, create hundreds of function-objects: JavaScript code does this all the time.

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


A second way is to use the support setTimeout has for additional arguments that it will supply as callback parameters. Thus the code could also be modified as so without the extra function (i) that was causing the "hint" warning. While this does create many timeouts (as in the original) it only uses a single function for the callback and avoids the extra closures.

第二种方法是使用支持setTimeout的附加参数,它将作为回调参数提供这些参数。因此,代码也可以进行修改,这样就不会产生“提示”警告的额外函数(i)。虽然这确实创建了许多超时(如最初的那样),但它仅为回调使用一个函数,并避免了额外的闭包。

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

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

Another way is to trick by creating the closure in another function, which effectively does the same thing as the original code. Arguably this is cleaner and easier to read than the original, even if not trying to eliminate the "hint" per-se.

另一种方法是在另一个函数中创建闭包,它有效地执行与原始代码相同的操作。可以说,这比原始版本更清晰、更容易阅读,即便不是试图消除“暗示”本身。

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);
}

#1


1  

If the outer (function (i)) function was removed then all the setTimeouts would use the same i because a new i (from the function parameter) would not be introduced (and it would lead to problems like this). As such the "hint" cannot be eliminated by simply removing it the outer anonymous function without changing other code as well. (Also see How do JavaScript closures work?)

如果删除了外部(函数(i)))函数,那么所有的setTimeouts都将使用相同的i,因为不会引入新的i(来自函数参数)(这将导致类似的问题)。因此,不能通过简单地删除外部匿名函数而不更改其他代码来消除“提示”。(还可以看到JavaScript闭包是如何工作的?)

While I disagree with this "hint" in general (and several other recommendations JSLint has), here are several different methods in which the "hint" can be avoided in this particular case besides merely disabling/ignoring the "hint".

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


One way to avoid the warning is to use setInterval once and using only a single callback function. The iteration (over i'th/the-point) is then advanced inside the callback inside and clearInterval is used when done. Note that the intent here is not to "improve performance" or eliminate the "hint" but show an alternative approach that some may perfer or find cleaner.

避免警告的一种方法是使用setInterval一次,并且只使用一个回调函数。然后迭代(在i'th/ The -point上)在回调内部进行,完成时使用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);
}

As a bonus it avoids the "hint" which I personally disagree with in general cases. Go ahead, create hundreds of function-objects: JavaScript code does this all the time.

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


A second way is to use the support setTimeout has for additional arguments that it will supply as callback parameters. Thus the code could also be modified as so without the extra function (i) that was causing the "hint" warning. While this does create many timeouts (as in the original) it only uses a single function for the callback and avoids the extra closures.

第二种方法是使用支持setTimeout的附加参数,它将作为回调参数提供这些参数。因此,代码也可以进行修改,这样就不会产生“提示”警告的额外函数(i)。虽然这确实创建了许多超时(如最初的那样),但它仅为回调使用一个函数,并避免了额外的闭包。

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

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

Another way is to trick by creating the closure in another function, which effectively does the same thing as the original code. Arguably this is cleaner and easier to read than the original, even if not trying to eliminate the "hint" per-se.

另一种方法是在另一个函数中创建闭包,它有效地执行与原始代码相同的操作。可以说,这比原始版本更清晰、更容易阅读,即便不是试图消除“暗示”本身。

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);
}