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

JavaScript for循环内按钮点击事件仅响应最后一次迭代值问题

问题根源

该问题与变量提升无关,核心原因有两点:

  • 所有动态生成的按钮内联onclick事件都统一调用全局作用域下的addBtn函数,没有绑定当前列表项的专属数据
  • 每次for循环迭代都会覆盖重写全局addBtn函数,前一次迭代定义的函数逻辑会被直接丢弃。循环结束后全局addBtn仅保留最后一次迭代的赋值,其闭包引用的索引值i对应数组最后一位元素,因此点击任意按钮都只会输出最后一项的食材名称。

另外原代码的按钮标签内多写了一个多余的},属于语法错误,需要一并删除。

修复方案

方案1:保留内联事件写法,直接传参(改动最小)

只需要在循环外统一定义一次addBtn,生成模板时直接把当前项的食材名作为参数传入事件调用即可,无需在循环内反复重写函数:

// 循环外单次定义函数,接收食材名参数
const addBtn = (ingredient) => {
  console.log(ingredient);
}

fetch('https://www.themealdb.com/api/json/v1/1/list.php?i=list')
  .then(res => res.json())
  .then(res => {
    for (let i = 0; i < res.meals.length; i++) {
      const ingredientName = res.meals[i].strIngredient;
      // 传入当前项的食材名,移除标签多余的}
      ingredientList.innerHTML += `<li>${ingredientName}
     <button onclick="addBtn('${ingredientName}')">Add</button> 
      </li>`;
    }
  }
);

方案2:动态创建元素绑定事件(推荐,无全局函数污染)

避免使用内联onclick,生成DOM元素时直接给按钮绑定事件,利用let的块级作用域特性,每个按钮的事件回调都能拿到对应迭代的食材数据:

fetch('https://www.themealdb.com/api/json/v1/1/list.php?i=list')
  .then(res => res.json())
  .then(res => {
    for (let i = 0; i < res.meals.length; i++) {
      const ingredientName = res.meals[i].strIngredient;
      // 创建DOM节点而非拼接innerHTML
      const li = document.createElement('li');
      li.append(ingredientName);
      const addBtn = document.createElement('button');
      addBtn.textContent = 'Add';
      // 单独给当前按钮绑定点击事件
      addBtn.addEventListener('click', () => {
        console.log(ingredientName);
      })
      li.append(addBtn);
      ingredientList.append(li);
    }
  }
);

注意:如果用var声明循环变量i,方案2需要额外做闭包处理,用let声明则自带块级作用域,无需额外处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 20:57:28