
本文介绍如何在 javascript 中避免冗长的 if/else 或 switch 判断,利用对象属性访问机制,通过字符串变量(如 'minor'、'major')动态获取对应数组,实现可扩展、易维护的音阶计算逻辑。
本文介绍如何在 javascript 中避免冗长的 if/else 或 switch 判断,利用对象属性访问机制,通过字符串变量(如 'minor'、'major')动态获取对应数组,实现可扩展、易维护的音阶计算逻辑。
在音乐理论工具或音阶生成器等实际应用中,常需根据用户选择(如点击“小调”按钮)动态加载不同音阶模式(minor、major、dorian、phrygian 等)。若为每种音阶硬编码条件分支,不仅代码重复、难以维护,还会随音阶种类增加而指数级膨胀。JavaScript 并不支持 PHP 风格的“可变变量”(如 $$keyScale),但可通过对象字面量 + 方括号属性访问优雅解决该问题。
核心思路是:将所有音阶数组统一注册到一个配置对象中,以字符串名称为键,数组本身为值;再通过变量(如 keyScale = 'minor')作为键名,安全访问目标数组。
以下是重构后的完整示例:
const notes = ['A','A#','B','C','C#','D','D#','E','F','F#','G','G#','A','A#','B','C','C#','D','D#','E','F','F#','G','G#','A'];
const minor = [0,2,3,5,7,8,10,12];
const major = [0,2,4,5,7,9,11,12];
const dorian = [0,2,3,5,7,9,10,12]; // 示例:新增音阶,无需修改主逻辑
// ✅ 将所有音阶集中管理为对象
const scales = {
minor,
major,
dorian
};
let keyRoot = 5;
let keyScale = 'minor'; // 可来自 UI 按钮、下拉菜单等
// ✅ 动态获取对应音阶数组,无需 if/else
const selectedScale = scales[keyScale];
if (!selectedScale) {
throw new Error(`Unknown scale: ${keyScale}`);
}
let output = '';
for (let i = 0; i < 8; i++) {
const songKey = keyRoot - 1 + selectedScale[i];
output += notes[songKey] + ' ';
}
console.log(output); // "C C# D E G G# A C "关键优势与注意事项:
立即学习“Java免费学习笔记(深入)”;
- ✅ 可扩展性强:新增音阶(如 pentatonic, blues)只需在 scales 对象中添加一行,主循环逻辑零修改;
- ✅ 类型安全提示:现代编辑器(VS Code)和 TypeScript 可对 scales[keyScale] 提供智能补全与类型推导;
- ⚠️ 务必校验存在性:使用 scales[keyScale] 前应检查返回值是否为数组(如上例中的 if (!selectedScale)),防止因拼写错误或非法输入导致 undefined[i] 报错;
- ? 避免使用 eval() 或 window[keyScale]:前者存在严重安全风险,后者依赖全局作用域且不可控,违背模块化设计原则;
- ? 进阶建议:可将 scales 定义为 Map 或封装为类(如 ScaleRegistry),便于后期支持元数据(如音阶描述、调式类型)或运行时动态注册。
这种模式本质上是“配置驱动开发”的典型实践——将变化点(音阶名称)从控制流中解耦,交由数据结构承载,大幅提升代码健壮性与可维护性。


















