如何实现按指定数量严格生成H/V字符的JavaScript函数?
精准生成指定数量H/V字符的解决方案
需要实现一个JavaScript函数,随机生成H或V字符,满足以下规则:
- 当
H的生成次数达到设定上限时,后续只能生成V - 当
V的生成次数达到设定上限时,后续只能生成H - 最终恰好得到指定数量的
H和V(例如各10个)
原代码中generateType函数存在逻辑缺陷,导致无法精准达成计数要求,以下是修复方案:
原代码核心问题分析
- 计数逻辑不同步:随机选中类型后,仅在类型未达上限时累加计数,但如果选中的类型已达上限,既未切换到合法类型,也未更新对应计数
- 边界处理遗漏:强制切换类型的分支中,没有同步更新对应的计数,导致返回类型正确但计数未增加
- 全局状态未重置:Web Worker是持久化运行的,多次调用时
totalH、totalV和textBack会保留旧值,导致后续生成结果错误 - 冗余无效代码:
generateTags中的tags.concat(tag)调用无意义(concat返回新数组,原代码未使用返回值,不会修改原数组)
修正后的完整代码
let letters = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q","r", "s", "t", "u", "v", "w", "x", "y", "z"]; let tags = []; let items = []; let index = 0; let textBack = ""; var hA = 0; var vA = 0; var minA; var maxA; let totalH = 0; let totalV = 0; function saveDATA(min, max, h, v){ minA = min; maxA = max; hA = Math.round(h / 50); vA = Math.round(v / 50); } function generateTags(totalTags){ let tag; for(let i = 0; i < totalTags; i++){ let r1 = Math.ceil(Math.random() * 15); let r2 = Math.ceil(Math.random() * 7); let r3 = Math.ceil(Math.random() * 5); let r4 = Math.ceil(Math.random() * 9); let r5 = Math.ceil(Math.random() * 17); tag = letters[r1] + letters[r2] + letters[r3] + letters[r4] + letters[r5]; if(tags.includes(tag)){ let random = Math.round(Math.random()); if(random == 1){ tags.push(tag); } } else{ tags.push(tag); tags.push(tag); items.push(tag); } if(totalTags < 2){ return tag; } } } // 修复后的类型生成函数 function generateType(h5, v5){ let selectedType; const canGenerateH = totalH < h5; const canGenerateV = totalV < v5; if (!canGenerateH) { // H已达上限,强制生成V并计数 selectedType = "V"; totalV += 1; } else if (!canGenerateV) { // V已达上限,强制生成H并计数 selectedType = "H"; totalH += 1; } else { // 两种类型都可生成,随机选择后同步计数 selectedType = Math.random() > 0.5 ? "H" : "V"; selectedType === "H" ? totalH++ : totalV++; } return selectedType; } function getRandomInt(min, max) { let minB = Math.ceil(Number(min)); let maxB = Math.floor(Number(max)); return Math.floor(Math.random() * (maxB - minB + 1)) + minB; } function generateTagsInsideItem(){ let totalTags = getRandomInt(minA, maxA); return totalTags; } function generateTagsItem(h4, v4){ let totalTags = generateTagsInsideItem(); let tagsStr = ""; for(let i = 0; i < totalTags; i++) { tagsStr += " " + generateTags(1); } let text = generateType(h4, v4) + " " + totalTags + " " + tagsStr; return text; } function generateDocumnet(id, itemsCount, horizontal, vertical) { // 每次生成前重置全局状态,避免旧数据干扰 totalH = 0; totalV = 0; textBack = ""; hA = Math.round(Number(horizontal) / 50); vA = Math.round(Number(vertical) / 50); for(let i = 0; i < itemsCount; i++){ textBack += "\n" + generateTagsItem(hA, vA); } } self.addEventListener("message", function(e) { saveDATA(e.data.minimum, e.data.maximum, e.data.horizontal, e.data.vertical); generateDocumnet(e.data.id, e.data.count, e.data.horizontal, e.data.vertical); this.postMessage({id: e.data.id , result: textBack}); }, false);
关键改动说明
- 重置全局状态:在
generateDocumnet开头重置totalH、totalV和textBack,确保每次调用都是独立的生成过程,解决Web Worker持久化导致的旧数据残留问题 - 重构类型生成逻辑:
- 优先判断边界情况(某类型已达上限),直接返回合法类型并同步计数
- 随机选择时立即更新对应计数,彻底避免“选中类型无法生成但未切换”的错误
- 清理冗余代码:移除无效的
tags.concat(tag)调用,将tags变量名改为tagsStr避免与全局数组冲突,提升代码可读性
内容的提问来源于stack exchange,提问作者Erzen Gaming
相关产品推荐
相关产品推荐

