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

为何JavaScript循环中用数组索引[i]无法播放音频,固定索引却可行?

循环绑定点击事件时音频路径失效的原因及解决方法

问题本质

你遇到的报错是因为**var声明的变量没有块级作用域**:循环执行时,所有事件监听器里的i都指向同一个全局变量。当循环结束后,i的值已经等于drum.length(也就是7),而你的playlist数组只有7个元素(索引范围0-6),playlist[7]是undefined,所以audio.src被设为无效值,导致音频加载失败。

而写死playlist[1]时,路径是有效的,所以能正常播放。

解决方法

方法1:用let声明循环变量i

let有块级作用域,每次循环都会创建一个独立的i变量,每个事件监听器引用的是当前循环的i值:

var audio = new Audio();
var playlist = ["sounds/crash.mp3","sounds/kick-bass.mp3","sounds/snare.mp3","sounds/tom-1.mp3","sounds/tom-2.mp3","sounds/tom-3.mp3","sounds/tom-4.mp3"];
var drum = document.querySelectorAll(".drum")

// 把var改成let
for (let i = 0; i < drum.length; i++) {
    drum[i].addEventListener("click", function play() {
        audio.src = playlist[i];
        audio.play();       
    });
}

方法2:用立即执行函数创建闭包

通过立即执行函数(IIFE)把当前循环的i值保存到函数作用域中,避免所有监听器共享同一个变量:

var audio = new Audio();
var playlist = ["sounds/crash.mp3","sounds/kick-bass.mp3","sounds/snare.mp3","sounds/tom-1.mp3","sounds/tom-2.mp3","sounds/tom-3.mp3","sounds/tom-4.mp3"];
var drum = document.querySelectorAll(".drum")

for (var i = 0; i < drum.length; i++) {
    // 用IIFE捕获当前i值
    (function(index) {
        drum[index].addEventListener("click", function play() {
            audio.src = playlist[index];
            audio.play();       
        });
    })(i);
}

方法3:使用forEach循环

forEach的回调函数会形成独立作用域,每个迭代的索引都是独立的:

var audio = new Audio();
var playlist = ["sounds/crash.mp3","sounds/kick-bass.mp3","sounds/snare.mp3","sounds/tom-1.mp3","sounds/tom-2.mp3","sounds/tom-3.mp3","sounds/tom-4.mp3"];
var drum = document.querySelectorAll(".drum")

drum.forEach(function(element, index) {
    element.addEventListener("click", function() {
        audio.src = playlist[index];
        audio.play();
    });
});

方法4:利用元素自定义属性存储索引

把索引存在按钮的dataset属性里,点击时从元素上获取对应索引:

var audio = new Audio();
var playlist = ["sounds/crash.mp3","sounds/kick-bass.mp3","sounds/snare.mp3","sounds/tom-1.mp3","sounds/tom-2.mp3","sounds/tom-3.mp3","sounds/tom-4.mp3"];
var drum = document.querySelectorAll(".drum")

for (var i = 0; i < drum.length; i++) {
    drum[i].dataset.index = i; // 给按钮存储对应索引
    drum[i].addEventListener("click", function play() {
        var index = this.dataset.index; // 获取当前按钮的索引
        audio.src = playlist[index];
        audio.play();       
    });
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 12:40:21