开发者问题收集

使用 Javascript 搜索数组中的项目

2016-12-18
80

我尝试添加一些代码,用户单击按钮后代码会生成 3 个数字(不重复,因此 245 可以,但 122 和 121 不可以)并将它们显示在屏幕上,每秒一个。为确保没有重复,我使用数组: var usedNums = []; 。然后,我创建数字( digit = Math.random() )并检查它是否已在数组中,如果不在,则添加它,如下所示:

if ($.inArray(digit, usedNums) !== -1) {
        newNums();
    } else {
        usedNums.push(digit);
        $('#memDigit').html(digit);

}

前几次,它可以正常工作,但当我第 10 次单击它时,我收到 Uncaught RangeError: Maximum call stack size reached 错误。救命!

以下是完整代码:

var usedNums = [];
var digit;
var amount = 3;

function newNums() {
    digit = Math.floor(Math.random() * 10);
    if ($.inArray(digit, usedNums) !== -1) {
        newNums();
    } else {
        usedNums.push(digit);
        $('#memDigit').html(digit);

    }

}

function createNums() {
    for (var i; i < amount; i++) {
        setTimeout(newNums, 1000);
    }
}

//$(document).ready(createNums);
2个回答

我认为您应该在每次数字生成完成后清空/重新初始化数组 usedNums。

Wadih M.
2016-12-18

如果 IE ≤ 10 不是问题,您可能希望利用 crypto.getRandomValues 一次性完成此操作。

getRandomValues 方法会用一系列该数组类型支持的范围内的随机值填充 TypedArray 。如果我们要求 10 个这样的值,那么实际上我们现在就拥有了 0-9 的数字哈希值(即数组的索引),该哈希值预先与随机值相关联,以便按(值)进行排序。结果将更加随机,而且 — 与“已看到此值,重试”模式不同 — 它应该在恒定时间内运行。

ES6:

const nums = [ ...crypto.getRandomValues(new Int16Array(10)) ]
  .map((sortVal, num) => [ sortVal, num ])
  .sort(([ a ], [ b ]) => a < b ? -1 : Number(a > b))
  .map(([ , num ]) => num)
  .slice(0, 3);

ES5:

var nums = [].slice.call(crypto.getRandomValues(new Int16Array(10)))
  .map(function(sortVal, num) { return [ sortVal, num ]; })
  .sort(function(a, b) { return a[0] < b[0] ? -1 : Number(a[0] > b[0]); })
  .map(function(pair) { return pair[1]; })
  .slice(0, 3);

细分:

  • new Int16Array(10) 创建一个长度为 10 的空 TypedArray
  • crypto.getRandomValues(...) 用随机值填充该数组
  • 我们将结果转换为常规数组
  • 我们将其映射到 [ randomVal, index ] 元组
  • 我们按随机值对其进行排序(记住明确强制转换为 Number,以覆盖 Safari sort 实现错误)
  • 我们映射到索引 —即 0-9 之间的数字
  • 我们只获取前三个值
Semicolon
2016-12-18