1

我目前正在做一些非常基本的事情,但我很难过。我想在二维数组中获取一个随机索引,并在每次 for 循环翻转时将其递增一。

var dice = [[],[]];

// Get totals.
for(var i = 0; i < 30000; i++) {
    var dieOne = Math.floor(Math.random() * 6 + 1);
    var dieTwo = Math.floor(Math.random() * 6 + 1);
        dice[[dieOne][dieTwo]]++;
    }

    // All index values equal 30,000 for some reason
    alert(dice[[1][3]]);

为什么这个 for 循环会将所有索引设置为 30,000?我是否错误地使用了 JavaScript 数组?

谢谢。

4

2 回答 2

2

你在做什么

似乎您误解了您正在做的事情的语法。目前相当于

var dieOne = Math.floor(Math.random() * 6 + 1);
var dieTwo = Math.floor(Math.random() * 6 + 1);
var foo;
foo = dieOne; // a number
foo = [foo];  // an array with one number in it
foo = foo[dieTwo]; // probably undefined, unlikely case of `dieTwo = 0`
                   // which would give back `dieOne`
dice[foo] = dice[foo] + 1; // most likely trying to add 1 to property `undefined`

然后你在做

foo = [1]; // an array length 1
foo = foo[3]; // undefined, it doesn't have an item here
foo = dice[foo]; // = dice[undefined] = undefined
alert(foo); // alerting "undefined"

你可能想做的事

看起来您实际上想要一个Array of 6 Arrays每个6 Numbers;构建你最喜欢的方式

var dice = [
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0]
];

然后让你的循环成为

var dieOne, dieTwo, i;
for(i = 0; i < 30000; ++i) {
    dieOne = Math.floor(Math.random() * 6); // indices start at 0 and
    dieTwo = Math.floor(Math.random() * 6); // 6 of them means max is 5
    dice[dieOne][dieTwo]++; // count the brackets here..
}

然后说你想知道你有多少次dieOne = 1, dieTwo = 3,你会看

dice[1][3]; // count the brackets again.
于 2013-11-02T00:38:14.950 回答
1

这虽然(不幸的是)在技术上是有效的 JavaScript,但不会做你想做的事:

dice[[dieOne][dieTwo]]

该表达式foo[bar]是对foo名为 的属性的引用bar。属性键始终是字符串或数字(技术上只是字符串,但如果我们谈论的是数组,将键视为数字更有意义)。因此,当 JavaScript 看到表达式时dice[[dieOne][dieTwo]],它会尝试强制[dieOne][dieTwo]转换为有效的属性键。古怪的情况如下:

  • [dieOne]计算结果为一个数组,该数组包含一个索引为 0 的元素,其值为dieOne; 让该中间结果在下文中称为foo
  • foo[dieTwo]foo计算对其索引为的属性的引用dieTwo
  • 因为,在循环的每次迭代中,dieTwo总是 > 0,并且foo是一个数组,其唯一有效索引是0,dieTwo超出范围。可悲的是,数组返回undefined而不是抛出错误。
  • 该值undefined被强制转换为字符串,因此可以用作属性键。从技术上讲,只有字符串是属性键;根据标准,数组是伪造的。值为"undefined"
  • 由于您的代码尚未为 分配值dice["undefined"],因此第一次尝试++将其初始值再次视为undefined。同样,不幸的是,它没有抛出异常,而是强制undefined转换为您想要的样子, number 0,递增到1,并将其分配给新定义的dice["undefined"]
    • 如果您的浏览器遵循 ES5 标准,undefined++则为NaN.
  • 由于遵循上述步骤,[dieOne][dieTwo]始终强制为,因此在循环的每次迭代中"undefined",所述属性dice都会递增一次,最终值为30000
    • 如果您的浏览器遵循 ES5 标准,无论您增加多少次,都会是NaN++NaN
  • 由于 ANY [foo][bar]where baris not 0,当被强制转换为属性键时,将"undefined"根据上述步骤,dice[[n][m]]始终等同于dice["undefined"]. 只是为了好玩,除了验证它不是并且因此我是正确的并且应该得到一个复选标记 =D 之外,尝试绝对是在哪里dice[[n][0]]n"undefined"30000

所以这就是为什么你会得到那个特定的结果。

JS 中没有真正的多维数组,如果您将其视为数组数组,您对语法的困惑就会少得多。然后你可以把它分解成几个步骤:

  • dice是数字数组的数组,
  • dice[n]一个数字数组也是如此,
  • dice[n][m]我想要的号码也是如此。

因此,您的正确程序大致如下所示:

/* We don't like undefined anymore, so make an array of 7 arrays of 7 zeroes */
/* (we need 7 because JS array indexes start at 0 and you're using values 1-6) */
var dice = [
    [0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0]
];
/* Now I'm tired of repeating myself, so let's DRY things up */
function roll() {
    return Math.floor(Math.random()*6) + 1;
}
var dieOne, dieTwo;
for ( var i = 0 ; i < 30000 ; i++ ) {
    dieOne = roll();
    dieTwo = roll();
    dice[dieOne][dieTwo]++;
}

最重要的部分是最后一行。

  • dice是一个数字数组,
  • dice[dieOne]一个数字数组也是如此,
  • 我们dice[dieOne][dieTwo]可以有意义地增加一个数字。
于 2013-11-02T02:01:16.363 回答