JS密码生成器输出不符预期 字符重复含空格问题排查
密码生成器故障排查与修复方案
故障根因
两类异常是代码逻辑错误共同导致的,具体问题点如下:
- 函数未正确调用:
choices = randomLower().concat(randomUpper, randomNumber, randomSymbol)这行代码里,randomUpper/randomNumber/randomSymbol没有加()执行,传入concat的是函数本身的引用,JS会把函数对象的完整源码转成字符串拼接,最终choices是「1个随机小写字母+三个函数的完整源码字符串」,里面包含大量缩进空格、关键字字符,随机取字符时自然会拿到多余空格,且高频出现源码里重复的字母(比如function里的n、t、f),表现为字符反复重复。 - 字符池逻辑设计错误:就算给三个函数加上括号执行,
concat也只会拼接1个小写、1个大写、1个数字、1个符号,总共4个字符的可选池,生成8位以上密码时必然出现大量重复。 - 变量未声明导致作用域污染:
click/useNumbers/useLower/useUpper/useSymbol/choices全部没有用let/const声明,属于隐式全局变量,多次点击生成、分支判断不匹配时,会残留上一次运行的旧值,进一步导致结果混乱。 - 分支覆盖不全:原代码只写了「全不选」「全选」两个分支的
choices赋值逻辑,其余用户选部分字符类型的分支没有给choices赋值,会直接读取全局残留的旧值,导致输出乱码、空格。 - 输入校验逻辑漏洞:第一次输入长度不在8-128区间时,第二次弹出的prompt输入结果没有做合法性校验,用户输入非数字、点取消都会直接往下执行,导致循环长度异常。
修复方案
- 所有变量统一在函数内用
let/const声明,避免全局污染 - 调整字符池逻辑:把用户选中的字符类型对应的生成函数存入数组,每次循环随机选一个函数执行,生成全新的随机字符,从根源避免重复
- 补全分支逻辑,只要用户选了至少一类字符,就把对应生成函数加入可选池
- 补全长度校验的循环逻辑,直到用户输入合法长度才继续
- 移除冗余的重复赋值逻辑,统一在密码生成完成后返回结果,由写入函数赋值到输入框
修复后核心代码
function randomLower() { return String.fromCharCode(Math.floor(Math.random() * 26) + 97); } function randomUpper() { return String.fromCharCode(Math.floor(Math.random() * 26) + 65); } function randomNumber() { return String.fromCharCode(Math.floor(Math.random() * 10) + 48); } function randomSymbol() { const symbol = "!@#$%^&*()_-<>[]}{"; return symbol[Math.floor(Math.random() * symbol.length)]; } const generateBtn = document.querySelector("#generate"); function writePassword() { const password = generatePassword(); const passwordText = document.querySelector("#password"); passwordText.value = password; } generateBtn.addEventListener("click", writePassword); function generatePassword() { // 循环校验密码长度,直到输入合法值 let pwdLength; while (true) { const input = prompt("How many characters?", "8-128"); pwdLength = parseInt(input); if (!pwdLength) { alert("Input is needed"); continue; } if (pwdLength < 8 || pwdLength > 128) { alert("Answer must be between 8 and 128"); continue; } break; } // 收集用户选中的字符类型 const charGenerators = []; const useNumbers = confirm("Include numbers?"); const useLower = confirm("Include lowercase letters?"); const useUpper = confirm("Include uppercase letters?"); const useSymbol = confirm("Include special characters?"); if (useNumbers) charGenerators.push(randomNumber); if (useLower) charGenerators.push(randomLower); if (useUpper) charGenerators.push(randomUpper); if (useSymbol) charGenerators.push(randomSymbol); // 未选任何类型直接返回 if (charGenerators.length === 0) { alert("At least one option is needed"); return ""; } // 循环生成密码,每次随机选一个生成器产出新字符 const pWord = []; for (let i = 0; i < pwdLength; i++) { const selectedGenerator = charGenerators[Math.floor(Math.random() * charGenerators.length)]; pWord.push(selectedGenerator()); } return pWord.join(""); }
内容的提问来源于stack exchange,提问作者Codeyg12
相关产品推荐
相关产品推荐

