Javascript函数用于循环

Ste*_* Lu 6 javascript

这是一个简单的JS循环不按预期运行的情况的示例,因为循环变量不在单独的范围内.

经常提出的解决方案是构造一个令人不愉快的循环代码,如下所示:

for (var i in obj) {
    (function() {
        ... obj[i] ... 
        // this new shadowed i here is now no longer getting changed by for loop
    })(i);
}
Run Code Online (Sandbox Code Playgroud)

我的问题是,这可以改进吗?我可以用这个:

Object.prototype.each = function (f) {
    for (var i in this) {
        f(i,this[i]);
    }
};

// leading to this somewhat more straightforward invocation
obj.each(
    function(i,v) {
        ... v ...
        // alternatively, v is identical to
        ... obj[i] ...
    }
);
Run Code Online (Sandbox Code Playgroud)

当我确定我需要一个"范围循环"?它看起来更干净,应该具有与常规for循环类似的性能(因为它以相同的方式使用它).

更新:似乎做事Object.prototype是一个巨大的禁忌,因为它几乎打破了一切.

这是一个不那么具有侵入性的实现:

function each (obj,f) {
    for (var i in obj) {
        f(i,obj[i]);
    }
}
Run Code Online (Sandbox Code Playgroud)

调用稍有变化

each(obj,
    function(i,v) {
        ... v ...
    }
);
Run Code Online (Sandbox Code Playgroud)

所以我想我已经回答了我自己的问题,如果jQuery这样做,不会真的出错.我忽略的任何问题都可以得到答案.

tif*_*fon 1

您的答案几乎涵盖了它,但我认为原始循环的更改值得注意,因为无论出于each()何种原因,当该函数不方便时,使用普通的 for 循环都是合理的。

更新:更改为使用与问题引用的示例类似的示例来比较不同的方法。该示例必须进行调整,因为该each()函数需要一个填充的数组来迭代。

假设以下设置:

var vals = ['a', 'b', 'c', 'd'],
    max = vals.length,
    closures = [],
    i;
Run Code Online (Sandbox Code Playgroud)

使用问题中的示例,原始循环最终创建 2n 个函数(其中 n 是迭代次数),因为每次迭代期间都会创建两个函数:

for (i = 0; i < max; i++) {
    closures[i] = (function(idx, val) {  // 1st - factoryFn - captures the values as arguments 
        return function() {              // 2nd - alertFn   - uses the arguments instead
            alert(idx + ' -> ' + val);   //                   of the variables
        };
    })(i, vals[i]);
}
Run Code Online (Sandbox Code Playgroud)

通过在循环启动之前创建一次工厂函数,然后重用它,可以将其减少为仅创建 n + 1 个函数:

var factoryFn = function(idx, val) {
    return function() {
        alert(idx + ' -> ' + val);
    };
};

for (i = 0; i < max; i++) {
    closures[i] = factoryFn(i, vals[i]); 
}
Run Code Online (Sandbox Code Playgroud)

这几乎相当于each()在这种情况下如何使用该函数,这也会导致总共创建 n + 1 个函数。工厂函数创建一次并立即作为参数传递给each().

each(vals, function(idx, val) {
    closures[idx] = function() {
        alert(idx + ' -> ' + val);
    };
});
Run Code Online (Sandbox Code Playgroud)

FWIW,我认为使用的一个好处each()是代码有点短,并且在传递到函数时正确创建工厂函数each()清楚地说明了这是它的唯一用途。在我看来,循环版本的一个好处for是执行循环的代码就在那里,因此它的性质和行为是完全透明的,而函数each()可能在不同的文件中定义,由其他人编写等。