Что касается JavaScript для() loop voodoo
Я некоторое время находился под впечатлением, что цикл for
может существовать только в следующем формате:
for (INITIALIZER; STOP CONDITION; INC(DEC)REMENTER)
{
CODE
}
Это, однако, наиболее определенно не так; взгляните на эту реализацию JavaScript Fisher-Yates Shuffle:
shuffle = function(o)
{
for (var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
};
Этот маленький фрагмент полностью ударяет меня по голове; как в мире так много происходит внутри простого объявления цикла? Я имею в виду... он даже не открывает скобу! Вся магия выполняется прямо внутри оператора for
. Было бы замечательно, если бы кто-то мог дать относительно подробное объяснение тому, как в мире этот вуду делает то, что он делает. Очень ценится заранее.
Ответы
Ответ 1
Обобщенный формат цикла for (не для цикла in-in) равен
for ( EXPRESSION_1 ; EXPRESSION_2 ; EXPRESSION_3 ) STATEMENT
Первый EXPRESSION_1 обычно используется для инициализации переменной цикла, EXPRESSION_2 является условием цикла, а EXPRESSION_3 обычно является приращением или декрементом, но нет правил, которые говорят, что они должны вести себя так. Это эквивалентно следующему циклу while:
EXPRESSION_1;
while (EXPRESSION_2) {
STATEMENT
EXPRESSION_3;
}
Запятые - это просто оператор, который объединяет два выражения в одно выражение, значение которого является вторым подвыражением. Они используются в цикле for, потому что каждая часть (разделенная точкой с запятой) должна быть одним выражением, а не несколькими операторами. На самом деле нет причин (кроме, может быть, сохранить некоторое пространство в файле), чтобы написать цикл for так же, как это эквивалентно:
shuffle = function(o) {
var j, x;
for (var i = o.length; i > 0; i--) {
j = parseInt(Math.random() * i);
x = o[i - 1];
o[i - 1] = o[j];
o[j] = x;
}
return o;
};
Ответ 2
shuffle = function(o){
for (
var j, // declare j
x, // declare x
i = o.length; // declare i and set to o.length
i; // loop while i evaluates true
j = parseInt(Math.random() * i), // j=random number up to i
x = o[--i], // decrement i, and look up this index of o
o[i] = o[j], // copy the jth value into the ith position
o[j] = x // complete the swap by putting the old o[i] into jth position
);
return o;
};
Это начинается с i, равного количеству позиций, и каждый раз, когда вы меняете карты я и j, где j - это случайное число до я каждый раз, согласно алгоритму.
Его можно было бы просто написать без путаницы с запятой, true.
Кстати, это не единственный тип цикла for в javascript. Существует также:
for(var key in arr) {
value = arr[key]);
}
Но будьте осторожны, потому что это также будет проходить через свойства объекта, в том числе, если вы передаете объект Array.
Ответ 3
INITIALIZER может объявлять и инициализировать несколько переменных. STOP CONDITION - это единственный тест (здесь он просто "i" ), а INCREMENTER - это выражение, которое должно выполняться каждый раз после тела (оператор запятой позволяет вам иметь несколько подвыражений, которые все исполняются). Тело цикла for - это просто оператор ";"
Ответ 4
Код, который вы цитируете, на мой взгляд запутан. Существуют более четкие способы написания одной и той же функциональности.
Однако ваше понимание в значительной степени правильное. Ниже приведен один и тот же код, за исключением пробелов и комментариев.
for (
// Initializer
var j, x, i = o.length;
// Continue condition
i;
// Operation to be carried out on each loop
j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x
)
// empty body, equivalent to { }
;
Гораздо понятнее записать эквивалент:
var j,x,i = o.length;
while(i) {
j = parseInt(Math.random() * i);
x = o[--i];
o[i] = o[j];
o[j] = x;
}
Существуют другие оптимизации, которые могут быть сделаны для удобства чтения, включая использование while(i > 0)
вместо while(i)
и разбиение --i
на i--
на отдельной строке.
На самом деле нет причин для существования(), кроме чтения. Эти два эквивалента:
{ // this block is to scope int i
int i=0;
while(i<100) {
myfunc(i);
i++;
}
}
for(int i=0; i<100; i++) {
myfunc(i);
}
Вы должны использовать то, что наиболее читаемо для данного времени. Я бы сказал, что автор вашего кода сделал обратное. Справедливости ради, он, возможно, сделал это для того, чтобы получить меньший JS файл для более быстрой загрузки (это может быть преобразование, которое может сделать автоматическое уплотнение кода).
Ответ 5
Синтаксис цикла for:
for (pre-block; condition; post-loop-block)
loop-block;
Сначала выполняется предварительный блок, определяются различные переменные.
В каждом цикле:
- проверить условие
- выполнить цикл-блок
- выполнить пост-цикл-блок
- повторить с 1.
Ответ 6
Они в значительной степени просто переместили тело цикла в секцию инкремента. Вы можете переписать цикл for как цикл while, чтобы получить представление о том, что он делает:
shuffle=function(o) {
var j; //Random position from 0 up to the current position - 1
var x; //temp holder for swapping positions
var i=o.length; //current position
while(i>0) { // Loop through the array
j = parseInt(Math.random()*i); //get a lower position
x = o[--i]; // decrement the position and store that position value in the temp var
o[i]=o[j]; // copy position j to position i
o[j]=x; // copy the temp value that stored the old value at position i into position j
}
return o;
}
Первые три var - это расширение начального словаря, проверка while - это условие остановки, а тело while - это то, что было сделано в части приращения для.
Изменить: Исправлено за комментарий Gumbo
Ответ 7
Это утверждение соответствует вашему первоначальному формату.
Оказывается, вы могли бы добавить более одного предложения каждого из них, используя "," (запятая)
Итак:
for (var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
Может быть проанализирован следующим образом:
for (var j, //INITIALIZER(s)
x,
i = o.length;
i; // STOP CONDITION ( i )
j = parseInt(Math.random() * i), // INC(DEC)REMENTER
x = o[--i],
o[i] = o[j],
o[j] = x); // CODE ( ; )
Как вы видите, он полностью соответствует вашему первоначальному формату.
Ответ 8
это полностью возвращается к синтаксису C, из которого javascript украл связку. основной трюк - это запятый оператор, который, кажется, появляется почти в любом другом месте, кроме петель
Ответ 9
Первое предложение инициализирует любые переменные, которые вы хотите использовать. Второе предложение действительно является условием остановки. Третье предложение включает любую логику, которая должна быть выполнена в конце каждой итерации. Несколько операторов могут быть разделены запятыми.