You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript动态更新变量无法作为数组索引引用对象值问题

网页音乐播放器八度切换功能失效问题修复

问题核心原因

这个bug和滑块事件监听、oct变量更新逻辑都没关系,本质是对JavaScript对象初始化的执行时机理解有偏差:
你在代码顶层定义const notes = { y: scale[oct].A }的逻辑,会在页面刚加载、代码从上到下执行到这一行时就立刻计算scale[oct].A的值——这时候oct还是初始值2,计算结果是固定数字440,这个440会被直接存到notes.y属性里,之后不会自动更新。
后续拖动滑块确实把全局变量oct改成了最新值,但你从来没有在oct更新后重新给notes.y赋值,所以notes.y永远是初始化时算出来的440,按键播放自然不会切换八度。你日志里看到oct值和滑块一致,只是因为全局变量本身更新了,但取频率的时候根本没用到这个最新的oct去重新查询scale数组,拿的是早就存死在notes里的旧值。

修复方案

核心原则是不要在初始化阶段把频率值写死,要在播放音符的时刻,用最新的oct值动态计算频率,以下两种改法任选其一即可:

方案1:按键时实时计算频率(推荐)

把按键映射改成存储音符名,不要提前存固定频率,每次触发按键事件时再用当前oct值取对应频率:

// 仅映射按键对应的音符名称,不提前计算固定频率
const notes = {
  y: 'A',
};

function keydownHandler(event) {
  // 统一转小写,兼容大写锁定状态下按Y的场景
  const key = event.key.toLowerCase();
  // 每次按键都用最新的oct值,动态读取对应八度的音符频率
  const freq = scale?.[oct]?.[notes[key]];
  console.log("keydown event: oct val =", oct, "frequency =", freq);
  if (freq) {
    playNote(freq);
  } else {
    console.log("仅Y键可播放音符,或当前八度无对应音符");
  }
}

方案2:滑块更新时同步刷新频率映射

如果你想保留notes存储频率的结构,就在滑块值变化的回调里,更新oct的同时同步刷新notes里存的频率值:

function handelChange(event) {
  oct = parseFloat(slider.value);
  console.log("oct Value:", oct);
  labelVal.innerHTML = oct;
  // oct更新后同步刷新notes里的频率取值
  notes.y = scale?.[oct]?.A;
  return oct;
}

其他待修正的小问题

代码里存在几处拼写和健壮性问题,虽然不触发当前bug,但建议修正避免后续出现异常:

  • 滑块事件回调名handelChange拼写错误,正确写法为handleChange
  • 振荡器创建函数名ceateOsc拼写错误,正确写法为createOsc
  • 给scale[oct]的取值加可选链?.,避免滑块滑到0、1位置时读取.A属性抛出JS错误

内容的提问来源于stack exchange,提问作者Fishbite

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 13:51:10