首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

JavaScript閉包陷阱:循環中綁定事件變量捕獲問題與解決方案

     編輯:程式設計綜合問答

問題代碼

$(document).ready(function(){
    for(var i = 0; i < 5; i++){
        $("#b"+i).bind("click", function(){
            alert(i); // 全部彈出 5
        });
    }
});

根本原因

變量提升 + 閉包捕獲引用:

  • `var i` 被提升到函數頂部,整個循環共享**同一個** `i` 變量
  • 點擊事件回調形成閉包,**引用**外層變量 `i`,而非複製其值
  • 循環結束時 `i=5`,點擊時讀取的是最終值 5

解決方案對比

深度理解:閉包與作用域鏈

// 等價於編譯器看到的代碼結構
function setup() {
    var i; // 提升到函數頂部
    for(i=0; i<5; i++) {
        // 這裡創建的函數對象,其[[Scope]]指向同一個包含變量i的活動對象
        var callback = function() { alert(i); };
        $("#b"+i).bind("click", callback);
    }
    // 循環結束 i=5,所有callback引用的i都是同一個變量,值為5
}

最佳實踐建議

  • 現代項目**直接使用 `let`/`const`**,徹底避免此類問題
  • 舊項目(IE兼容)使用 **IIFE** 或 **jQuery.data()**
  • Eslint 規則 `no-loop-func` 可自動檢測此風險
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
方案代碼原理推薦度
1. IIFE(立即執行函數)
for(var i=0; i<5; i++){
    (function(idx){
        $("#b"+idx).click(function(){ alert(idx); });
    })(i);
}
創建新作用域,捕獲當前值副本⭐⭐⭐ 經典兼容
2. let 塊級作用域 (ES6+)
for(let i=0; i<5; i++){
    $("#b"+i).click(function(){ alert(i); });
}
每次迭代創建新綁定,天然解決⭐⭐⭐⭐⭐ 現代首選
3. jQuery data屬性
for(var i=0; i<5; i++){
    $("#b"+i).data("index", i).click(function(){
        alert($(this).data("index"));
    });
}
將值存儲在DOM元素上⭐⭐ 適用簡單場景
4. 箭頭函數 + 參數默認值
for(var i=0; i<5; i++){
    $("#b"+i).click(((idx)=>()=>alert(idx))(i));
}
利用默認參數捕獲當前值⭐⭐ 技巧性較強