Альтернатива для цикла JavaScript: repeat (n, function (i) {...}); - PullRequest
6 голосов
/ 08 февраля 2011

Это обычный цикл for:

for (var i = 0; i < n; i++) { ... }

Он используется для итерации массивов, а также просто для повторения некоторого процесса n раз.

Я использую вышеупомянутую форму, но она отталкивает меня. Заголовок var i = 0; i < n; i++ выглядит ужасно и должен быть переписан буквально каждый раз, когда он используется.

Я пишу этот вопрос, потому что я нашел альтернативу:

repeat(n, function(i) { ... });

Здесь мы используем функцию repeat, которая принимает два аргумента:
1. количество итераций,
2. функция, тело которой представляет процесс, который повторяется.

«Кодовый код» будет выглядеть так:

function repeat(n, f) {
    for (var i = 0; i < n; i++) {
        f(i);
    }
} 

(Мне известно о влиянии на производительность наличия двух дополнительных «уровней» в цепочке областей действия процесса)

Кстати, для тех из вас, кто использует библиотеку jQuery, вышеупомянутая функциональность может быть реализована из коробки с помощью метода $.each, например:

$.each(Array(n), function(i) { ... });  

Так что ты думаешь? Является ли эта repeat функция допустимой альтернативой нативному циклу for? Каковы недостатки этой альтернативы (кроме производительности - я знаю об этом)?

Native:

for (var i = 0; i < 10; i++) {
    // do stuff
}

Альтернатива:

repeat(10, function(i) {
    // do stuff
});

Ответы [ 5 ]

10 голосов
/ 08 февраля 2011

Вы говорите, что хотите революцию ... Ну, вы знаете: ruby ​​сделал это как раз перед (?)

Number.prototype.times = function(func) { 
    for(var i = 0; i < Number(this); i++) {
        func(i); 
    }
}

означает

(50).times(function(i) {
    console.log(i)
})

В любом случае, не боритесь с С, вы всегда проиграете: -P

5 голосов
/ 08 февраля 2011

это интересная мысль, но если вам не нравится синтаксис цикла, вы всегда можете сделать цикл другого типа:

var i = arr.length; 
while (i--) {
    // do stuff
}

в обратном порядке цикл обычно быстрее, чем цикл for,

2 голосов
/ 08 февраля 2011

Чтобы решить проблему отсутствия оператора break, как уже упоминали другие, я бы решил это следующим образом:

function repeat(n, f) {
    for (var i = 0; i < n; i++) {
        if (f(i) === false) return;
    }
}

Тогда возврат false из обработчика цикла будет эквивалентен break.

Еще один недостаток - изменение контекста.Вы можете добавить опцию проксирования контекста в обработчики цикла:

function repeat(context, n, f) {
    if (!f) f = n, f = context, context = window;

    for (var i = 0; i < n; i++) {
        if (f.call(context, i) === false) return;
    }
}

Теперь преимущество состоит в том, что индекс сохраняется в области действия функции, чтобы избежать общейошибка:

for (var i = 0; i < 10; i++) {
    setTimeout(function () {
        alert(i); // Will alert "10" every time
    }, 1000);
}

repeat(10, function (i) {
    setTimeout(function() {
        alert(i); // Will alert "0", "1", "2", ...
    }, 1000);
});
1 голос
/ 08 февраля 2011

Помимо того, что вы уже заявили, основной недостаток, который я вижу, состоит в том, что выражение «возврат» будет работать по-другому. (Именно поэтому я часто использую «for» вместо «$ .each» на своих предприятиях.)

1 голос
/ 08 февраля 2011

Кажется, довольно актуально.Я, честно говоря, не думаю, что производительность слишком сильно снизится.Но есть, однако, один большой недостаток, который легко исправить: оператор break .

function repeat(n, f) {
   for (var i = 0; i < n; i++) {
      var tcall=i;
      tcall.die=function(){i=n}
      f.call(tcall);
   }
}  

Таким образом, вы сможете вызвать this.die() вместо break;, которыйдумаю выкинет ошибку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...