所以我正在阅读关于洗牌的内容。然后我遇到了这个脚本:
shuffle = function(o){ //v1.0
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
它甚至根本没有{}
!但它很有效,就像魔术一样。我很想知道它是如何工作的。(还有一堆逗号。)
所以我正在阅读关于洗牌的内容。然后我遇到了这个脚本:
shuffle = function(o){ //v1.0
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
它甚至根本没有{}
!但它很有效,就像魔术一样。我很想知道它是如何工作的。(还有一堆逗号。)
后面的for ()
可以是任何语句;可以是带有花括号的东西,也可以是单个表达式,也可以是空表达式。for (...);
相当于for (...) {}
。当然,这只能与自然终止的 for 循环一起使用,否则您将手上有一个无限循环。
逗号实际上是二级分号;它们生成大部分单独的语句,但它们可以在 for 循环中工作(以及其他地方;这是对它们的非常草率的定义)。
for (
// initialisation: declare three variables
var j, x, i = o.length;
// The loop check: when it gets to ``!i``, it will exit the loop
i;
// the increment clause, made of several "sub-statements"
j = parseInt(Math.random() * i),
x = o[--i],
o[i] = o[j],
o[j] = x
)
; // The body of the loop is an empty statement
这可以以更易读的形式表示为:
for (
// initialisation: declare three variables
var j, x, i = o.length;
// The loop check: when it gets to ``!i``, it will exit the loop
i;
// note the increment clause is empty
) {
j = parseInt(Math.random() * i);
x = o[--i];
o[i] = o[j];
o[j] = x;
}
作为一个while循环,可能是:
var j, x, i = o.length;
while (i) {
j = parseInt(Math.random() * i);
x = o[--i];
o[i] = o[j];
o[j] = x;
}
首先,我想指出这样的循环被认为是不好的风格,因为它非常不可读并且会引起很多混乱。这是一个典型的优化出错的例子。
查看规格,您会发现for(...)
后面必须有一个声明。它可以是任何语句,包括块。所以所有这些都是有效的:
for (...)
foo; // expression statement
,
for(...)
{
// block statement
}
,
for(...)
if(...) // If statement
foo;
, 而且当然
for (...)
;
因为 " ;
" 是空语句。它什么也不做,但足以使for(...);
语法有效。
现在,逗号。请注意,括号的内容必须是三个表达式,(每个都是可选的),用分号分隔。几乎“一切”都可以作为表达式,包括以逗号分隔的表达式列表。虽然鲜为人知,但这些工作基本上在 JS 中无处不在,不仅在for
循环中。他们只是一个接一个地被评估。
所以,你的循环可以像这样重写
shuffle = function(o) {
var j, x, i = o.length;
while (i) { // for-loops are just while-loops in disguise
j = parseInt(Math.random() * i), // even better: replace , by ;
x = o[--i],
o[i] = o[j],
o[j] = x;
}
return o;
};
此外,x = o[--i]
应写为i--; x = o[i]
.
对于我们不需要 {} 的单个语句,每个计算都在同一个语句中,但也在这个语句中;(句尾用了句终止符)表示下一条语句不属于for语句。无论逻辑是什么,for 语句都是一样的。
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, x, i = o.length;// Initialization
i;// Work until i is zero
j = parseInt(Math.random() * i),
x = o[--i], o[i] = o[j], o[j] = x);//Here he is computing his logic
如果都在一行上,则不需要括号。很多时候,在括号内的第三部分中,您只会看到i++
,或类似的东西。真的,你可以在那里做很多不同的事情。如果您能够在第三部分中打包所有内容,那么您甚至不需要for
循环体。
for (first section; second section; third section);
第一节
变量被声明和初始化。这些变量包含在循环的范围内。
第二节
这是每次循环通过时检查的条件。
第三节
每次通过循环后运行的代码。它可以像增加一个变量一样简单,也可以像……那么复杂,只要语法正确,您可以在线放置任何东西。
看起来我没有正确阅读循环。
在这种情况下,评估发生在 for 循环的条件内。
所以一个 for 循环包含三个部分
for (initial variables; end cases; what to do every iteration)
您定义一些初始的东西并使用o
它们传递给函数,定义一个结束情况,然后在每次迭代中计算一些东西。最后,o
有一个新值并返回。
所有的工作实际上都是在for
声明的括号内完成的。循环没有明确的主体,所以;
最后只是说主体是一个空语句。
(,
逗号)运算符从左到右计算表达式,并返回最右边的值。
循环基本上相当于:
for(var j, x, i = o.length; i > 0;)
{
j = parseInt(Math.random() * i--);
x = o[i];
o[i] = o[j];
o[j] = x
}