Math.round() 与 Math.floor()
首先要注意的是:Math.round() 在处理Math.random() 返回的值时永远不是正确的函数。它应该是Math.floor(),然后你不需要length 上的-1 更正。这是因为Math.random() 返回的值是>= 0 和< 1。
这有点棘手,所以让我们举一个具体的例子:一个包含三个元素的数组。正如vihan1086's excellent answer 解释的那样,这个数组的元素编号为0、1 和2。要从该数组中选择一个随机元素,您希望获得这三个值中的任何一个的机会均等。
让我们看看Math.round( Math.random() * array.length - 1 ) 的效果如何。数组长度为3,因此我们将Math.random() 乘以2。现在我们有一个值n,即>= 0 和< 2。我们将该数字四舍五入到最接近的整数:
如果n 是>= 0 和< .5,则四舍五入为0。
如果n 是>= .5 和< 1.5,则四舍五入为1。
如果n 是>= 1.5 和< 2,则四舍五入为2。
到目前为止一切顺利。我们有机会获得我们需要的三个值中的任何一个,0、1 或 2。但是 有什么机会呢?
仔细查看这些范围。中间范围(.5 到 1.5)是其他两个范围(0 到 .5 和 1.5 到 2)的两倍。我们有 25% 的机会获得0,50% 的机会获得1,以及 25% 的机会获得@987654362,而不是三个索引值中任何一个的机会均等@。哎呀。
相反,我们需要将Math.random() 的结果乘以3 的整个数组长度,所以n 是>= 0 和< 3,然后将结果取平:Math.floor( Math.random() * array.length ) 它的工作原理是这样的:
如果n 是>= 0 和< 1,它会跳转到0。
如果n 是>= 1 和< 2,它会下降到1。
如果n 是>= 2 和< 3,它会落地到2。
现在我们显然有相同的机会达到0、1 或2 三个值中的任何一个,因为每个范围的长度相同。
保持简单
这里有一个建议:不要在一个表达式中编写所有这些代码。将其分解为不言自明且有意义的简单函数。以下是我喜欢执行此特定任务的方式(从数组中选择一个随机元素):
// Return a random integer in the range 0 through n - 1
function randomInt( n ) {
return Math.floor( Math.random() * n );
}
// Return a random element from an array
function randomElement( array ) {
return array[ randomInt(array.length) ];
}
那么剩下的代码就直截了当:
var examples = [ 1, 2, 3, 56, "foxy", 9999, "jaguar", 5.4, "caveman" ];
var example = randomElement( examples );
console.log( example );
看看这种方式有多简单?现在,您不必每次想从数组中获取随机元素时都进行数学计算,只需调用 randomElement(array)。