<p>Math.random() 生成 [0,1) 区间随机数,永远小于 1;生成数字验证码用 Math.floor(Math.random() * 10) 最安全,避免 round 或 parseInt;混合验证码需预定义剔除易混淆字符的池子;安全场景应优先使用 crypto.getRandomValues()。</p>
很多人误以为 Math.random() 可能返回 1,实际它**永远小于 1**,最大值趋近于 0.999...。这点直接影响区间缩放逻辑——如果你写成 Math.floor(Math.random() * (max - min + 1)) + min,在整数场景下会多出一个值,导致越界或分布不均。
Math.floor(Math.random() * 10) 最安全4 位纯数字验证码(如 "3821")本质是 4 次独立的 0–9 随机整数采样。关键点在于:每个数字必须等概率、无偏移。
Math.random() * 10 输出范围是 [0, 10),Math.floor() 后正好是 0–9 的整数(共 10 个)Math.round():它会让 0 和 9 的概率只有其他数字的一半(因为 0.5 向上取整,0.499… 向下取整)parseInt(Math.random() * 10):字符串隐式转换可能截断小数,但语义不清且不比 Math.floor 更可靠想生成类似 "A7kP" 的 4 位混合码,常见错误是写 String.fromCharCode(65 + Math.floor(Math.random() * 52))——这会混入 ASCII 中的非字母符号(比如 `[`, ``, `]` 等),因为大写 A–Z 是 65–90,小写 a–z 是 97–122,中间有 6 个非字母字符。
const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789'(注意跳过易混淆字符 O/0, l/1, I)chars[Math.floor(Math.random() * chars.length)]
crypto.getRandomValues()?如果验证码用于登录、重置等安全敏感场景,Math.random() **不满足密码学安全要求**——它的输出可预测,且不同浏览器实现差异大。但对前端简单展示型验证码(如图片上模糊显示、仅防脚本批量提交),Math.random() 足够。
crypto.getRandomValues() 是真随机,但需要 Uint8Array,API 更重,且在某些旧环境(如 IE)不可用Math.random() + Math.floor() 组合仍是合理选择