2

考虑以下代码块,重复运行(jsFiddle):

var length = 50,
  xOffset = 0,
  yOffset = 0;
for (var a = 0; a < 100; ++a) { // just so we can see it "break"
  for (var l = 1; l <= length; l++) {
    var percentComplete = l / length,
      scaledPercent = (.5 - Math.abs(percentComplete - .5)) * 2,
      shake = 0,
      shakeTries = 0,
      deviationCeil = Math.ceil(10 * scaledPercent);
    if (Math.random() < .1 || Math.abs(xOffset) > deviationCeil)
      do {
        shake = Math.floor(Math.random() * 3) - 1;
        if (++shakeTries > 100) throw "X shake exceeded"
    }
    while (Math.abs(xOffset + shake) > deviationCeil);
    xOffset += shake;
    shakeTries = 0; // if we set shake = 0 here, everything works!
    if (Math.random() < .1 || Math.abs(yOffset) > deviationCeil)
      do {
        shake = Math.floor(Math.random() * 3) - 1;
        if (++shakeTries > 100) throw "Y shake exceeded"
    }
    while (Math.abs(yOffset + shake) > deviationCeil);
    yOffset += shake;
  }
}

重复运行时,会抛出“超出 Y 震动”异常(永远不会抛出“超出 X 震动”)。

shake解决方案是在 Y 块之前设置为 0: shake = shakeTries = 0

我不明白为什么会这样。shake在这两个块中,我们首先指定为摇动,因此在进入do块之前,到底是什么并不重要。我对do...while(以及我使用它的原因)的理解是它在测试条件之前首先执行它的块。

shake那么,当我在块之前没有重置时,为什么它会失败(不是每次都失败)do

4

1 回答 1

3

如果我们添加一些额外的{and ,这种奇怪的行为会变得更加明显}。让我们首先看一下 X 部分。一开始,shake 和shakeOffset 都等于0。

if (Math.random() < .1 || Math.abs(xOffset) > deviationCeil) {
  do {
    shake = Math.floor(Math.random() * 3) - 1;
    if (++shakeTries > 100) throw "X shake exceeded"
  } while (Math.abs(xOffset + shake) > deviationCeil);
}
xOffset += shake;

此时,shake 具有上一个块中最后使用的任何值(-1、0 或 1)。然后我们进入Y部分:

shakeTries = 0; // if we set shake = 0 here, everything works!
if (Math.random() < .1 || Math.abs(yOffset) > deviationCeil) {
  do {
    shake = Math.floor(Math.random() * 3) - 1;
    if (++shakeTries > 100) throw "Y shake exceeded"
  } while (Math.abs(yOffset + shake) > deviationCeil);
}
yOffset += shake;

如果我们不满足条件(Math.random() < .1 || Math.abs(yOffset) > deviationCeil),那么我们do...while完全跳过并将 X 部分的抖动值添加到 yOffset。

于 2013-05-24T02:19:53.130 回答