
本文介绍如何用简洁、可扩展的方式动态构建 JavaScript 字符串变量 j 和 k,避免冗长的 16 种 if/else if 组合;核心是基于数组映射关系与条件拼接逻辑,实现按 xOct 阈值自动分流、格式化封装及后缀添加。
本文介绍如何用简洁、可扩展的方式动态构建 javascript 字符串变量 `j` 和 `k`,避免冗长的 16 种 `if/else if` 组合;核心是基于数组映射关系与条件拼接逻辑,实现按 `xoct` 阈值自动分流、格式化封装及后缀添加。
在实际开发中,当面对多个并行条件判断(如 bOct > 3、cOct > 3 等)并需据此向不同目标变量动态追加内容时,硬编码 if 分支不仅易出错、难维护,更严重违背 DRY(Don’t Repeat Yourself)原则。原代码中试图穷举 4 个变量的 2⁴ = 16 种布尔组合,显然不可持续。理想解法应具备声明性、可迭代性与可配置性——即:将变量对(如 b/f 对应 bOct)、阈值规则、格式模板分离,再通过循环或函数式逻辑统一处理。
以下为优化后的完整实现方案,已整合进原始上下文,并增强健壮性与可读性:
const pc = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
const text1 = document.getElementById("text1");
const text2 = document.getElementById("text2");
window.onload = fetch;
function fetch() {
// 1. 随机生成音名索引与八度数
const [bPc, cPc, dPc, ePc, fPc, gPc, hPc, iPc] =
Array(8).fill().map(() => Math.floor(Math.random() * pc.length));
const [bOct, cOct, dOct, eOct] =
Array(4).fill().map(() => Math.floor(Math.random() * 6));
// 2. 映射音名:前四组用于 j(>3 时),后四组用于 k(≤3 时)
const namesForJ = [pc[bPc], pc[cPc], pc[dPc], pc[ePc]]; // b, c, d, e
const namesForK = [pc[fPc], pc[gPc], pc[hPc], pc[iPc]]; // f, g, h, i
const octaves = [bOct, cOct, dOct, eOct];
// 3. 动态构建 j 和 k(核心逻辑)
let j = "", k = "";
octaves.forEach((oct, idx) => {
const nameJ = namesForJ[idx];
const nameK = namesForK[idx];
if (oct > 3) {
j += `${nameJ}${oct} `;
} else {
k += `${nameK}${oct} `;
}
});
// 4. 格式化:添加括号(仅当含多个项)、追加 "/w"、清理尾空格
const formatSegment = (str) => {
str = str.trim();
if (str === "") return "";
const hasSpace = str.includes(" ");
return `${hasSpace ? "(" : ""}${str}${hasSpace ? ")" : ""}/w`;
};
j = formatSegment(j);
k = formatSegment(k);
// 5. 输出到 DOM
text1.textContent = j;
text2.textContent = k;
}
✅ 关键优势说明:
- 消除重复逻辑:使用 forEach 遍历 octaves 数组,天然覆盖全部 4 个变量,无需手动写 4 行三元运算符;
- 清晰的数据映射:namesForJ 与 namesForK 显式声明了“同一八度下该选哪个音名”,语义一目了然;
- 可复用的格式化函数:formatSegment() 封装了括号包裹、空值处理、后缀添加等共性逻辑,便于后续扩展(如支持其他分隔符或前缀);
- 严格空格控制:.trim() 确保无首尾空格,避免 "(C4 )/w" 类错误;includes(" ") 比 indexOf(" ") !== -1 更直观;
- DOM 安全输出:使用 textContent 替代 innerHTML,防止潜在 XSS(除非明确需渲染 HTML)。
⚠️ 注意事项:
- 若未来需支持更多变量(如增加 lOct, mOct),只需扩展 octaves 数组及对应 namesForJ/namesForK,逻辑零修改;
- 阈值 3 可抽取为常量(如 const THRESHOLD = 3;),提升可配置性;
- 当前随机逻辑未保证音名唯一性,如需去重,可在生成 pc[...] 后加入 Set 过滤步骤。
此方案将原本脆弱、爆炸式增长的分支逻辑,转化为线性、可推演的数据驱动流程,是 JavaScript 中处理多条件字符串聚合的典型工程实践。










