JavaScript的閉包特性如何給迴圈中的對象添加事件(一)

来源:https://www.cnblogs.com/xiaohan170208/archive/2019/08/22/JavaScript.html

初學者經常碰到的,即獲取HTML元素集合,迴圈給元素添加事件。在事件響應函數中(event handler)獲取對應的索引。但每次獲取的都是最後一次迴圈的索引。原因是初學者並未理解JavaScript的閉包特性。 1. <!DOCTYPE HTML> 2. <html> 3. <head> 4. < ...


    初學者經常碰到的,即獲取HTML元素集合,迴圈給元素添加事件。在事件響應函數中(event handler)獲取對應的索引。但每次獲取的都是最後一次迴圈的索引。原因是初學者並未理解JavaScript的閉包特性。

1. <!DOCTYPE HTML>

2.  <html>

3.  <head>

4.  <meta charset="utf-8" />

5.  <title>閉包演示</title>

6.  <style type="text/css">

7.      p {background:gold;}

8.  </style>

9.  <script type="text/javascript">

10.function init() {

11.    var pAry = document.getElementsByTagName("p");

12.    for( var i=0; i<pAry.length; i++ ) {

13.         pAry[i].onclick = function() {

14.         alert(i);

15.    }

16.  }

17.}

18.</script>

19.</head>

20.<body οnlοad="init();">

21.<p>產品 0</p>

22.<p>產品 1</p>

23.<p>產品 2</p>

24.<p>產品 3</p>

25.<p>產品 4</p>

26.</body>

27.</html>

 

以上場景是初學者經常碰到的。即獲取HTML元素集合,迴圈給元素添加事件。在事件響應函數中(event handler)獲取對應的索引。但每次獲取的都是最後一次迴圈的索引。

原因是初學者並未理解JavaScript的閉包特性。通過element.οnclick=function(){alert(i);}方式給元 素添加點擊事件。響應函數function(){alert(i);}中的 i 並非每次迴圈時對應的 i(如0,1,2,3,4)而是迴圈後最後 i 的值5。 或者說迴圈時響應函數內並未能保存對應的值 i,而是最後一次i++的值5。

瞭解了原因,下麵就由幾種方式可與解決:

1、將變數 i 保存給在每個段落對象(p)上

1.  function init1() {

2.    var pAry = document.getElementsByTagName("p");

3.    for( var i=0; i<pAry.length; i++ ) {

4.       pAry[i].i = i;

5.       pAry[i].onclick = function() {

6.          alert(this.i);

7.       }

8.    }

9.  }

2、將變數 i 保存在匿名函數自身

1.  function init2() {

2.    var pAry = document.getElementsByTagName("p");

3.    for( var i=0; i<pAry.length; i++ ) {

4.     (pAry[i].onclick = function() {

5.          alert(arguments.callee.i);

6.      }).i = i;

7.    }

8.  }

3、加一層閉包,i 以函數參數形式傳遞給內層函數

1.  function init3() {

2.    var pAry = document.getElementsByTagName("p");

3.    for( var i=0; i<pAry.length; i++ ) {

4.     (function(arg){

5.         pAry[i].onclick = function() {

6.            alert(arg);

7.         };

8.     })(i);//調用時參數

9.    }

10.}

4、加一層閉包,i 以局部變數形式傳遞給內層函數

1.  function init4() {

2.    var pAry = document.getElementsByTagName("p");

3.    for( var i=0; i<pAry.length; i++ ) {

4.      (function () {

5.        var temp = i;//調用時局部變數

6.        pAry[i].onclick = function() {

7.          alert(temp);

8.        }

9.      })();

10.  }

11.}

5、加一層閉包,返回一個函數作為響應事件(註意與3的細微區別)

1.  function init5() {

2.    var pAry = document.getElementsByTagName("p");

3.    for( var i=0; i<pAry.length; i++ ) {

4.     pAry[i].onclick = function(arg) {

5.         return function() {//返回一個函數

6.         alert(arg);

7.       }

8.     }(i);

9.    }

10.}

6、用Function實現,實際上每產生一個函數實例就會產生一個閉包

1.  function init6() {

2.      var pAry = document.getElementsByTagName("p");

3.      for( var i=0; i<pAry.length; i++ ) {

4.        pAry[i].onclick = new Function("alert(" + i + ");");//new一次就產生一個函數實例

5.      }

6.  }

7、用Function實現,註意與6的區別

1.  function init7() {

2.      var pAry = document.getElementsByTagName("p");

3.      for( var i=0; i<pAry.length; i++ ) {

4.           pAry[i].onclick = Function('alert('+i+')');

5.      }

6.  }


您的分享是我們最大的動力!

更多相關文章
  • 源碼: ...
  • 簡介 Socean.RPC是一個.Net下的高性能RPC框架,框架以高性能、高穩定性為目標,底層基於socket,代碼簡潔,總代碼量大約在2000行,無第三方庫引用,框架性能較高,在雙核i5筆記本上可達10w+每秒的處理量,支持10000長連接消息發送(每秒發10個短消息),均穩定運行,記憶體和cpu ...
  • 在項目的bin\debug\netcoreapp${Version}下麵能夠找到這個${AppName}.runtimeconfig.json文件,簡單來說,它就是用來定義應用程式所用的共用框架(.Net Core App)以及運行時選項 的一個文件。 一個簡單的例子 1、用來決定以哪個版本的.ne ...
  • 導出至Excel是非常常見,我們可以用很多類庫,例如Aspose、NOPI、Interop,在這裡我們使用微軟自家的工具。我的WPF綁定的ObservableCollection<T>集合。 該方法還不止這麼多,還涉及到了1-27 = A-Z 的適配,如以下方法。 最後我們獲取數據給方法,下麵是設計 ...
  • 本文主要參照https://www.bilibili.com/video/av42364337/?p=4 英文幫助文檔:https://identityserver4.readthedocs.io/en/latest/ 中文幫助文檔:http://www.identityserver.com.cn ...
  • 一、Swagger是什麼 Swagger 是一款RESTFUL介面的、基於YAML、JSON語言的文檔線上自動生成、代碼自動生成的工具。 二、如何在項目中加入Swagger Swagger安裝引用 右鍵Web項目依賴項>管理NuGet程式包>在搜索框輸入"Swashbuckle.AspNetCore ...
  • 本次應用DevExpress和C#語言製作了一個批量添加水印的程式,看界面效果圖: 界面中既可以進行文字水印添加,也可以圖片水印添加,同時還可以對水印的位置進行設置,比較實用! 文字水印的具體添加情況,看圖: 還可以文字的預覽: 整個文字水印的預覽: 同時圖片的水印預覽: 最後顯示下圖片的水印效果: ...
  • 摘要 本文將介紹如何通過VS2019創建Xamarin.Forms應用程式,以及如何進行調試。 前言 本文介紹Xamarin.Froms應用程式的創建和調試。 開發環境 1.Visual Studio 2019 2.Xamarin.Forms 3.6.0.344457 創建 1.打開VS2019,選 ...
一周排行
  • 該方式是直接對屏幕進行截圖操作UserControl chartContainPanel = new UserControl();Graphics graph = chartContainPanel.CreateGraphics();Size s = chartContainPanel.Size;B... ...
  • dotnetcore3.1 WPF 中使用依賴註入 Intro 在 ASP.NET Core 中預設就已經集成了依賴註入,最近把 "DbTool" 遷移到了 WPF dotnetcore 3.1, 在 WPF 中我們也希望能夠使用依賴註入,下麵來介紹一下如何在 WPF dotnetcore3.1 中 ...
  • 原來的C 程式都有Main的,現在用vs新建一個Wpf項目,啟動似乎變成App.xmal,前期項目中為了獲取啟動參數,很是折騰了一番: 1.先是修改App.xaml,添加StartUp事件 2.然後編輯Application_Startup,判斷e.Args數組 總感覺跟又臭又長的裹腳布一樣,不爽。 ...
  • 冒泡排序原理:(升序)通過當前位置數和後一個位置數進行比較 如果當前數比後一個數大 則交換位置, 完成後 比較基數的位置變成下一個數。直到數組末尾,當程式運行完第一遍 最大的數已經排序到最後一個位置了。次數可以減少迴圈數不用管最後一個數 降序排序同理 不過是把比較方式變成判斷當前數是否小於下一個數 ...
  • 一、前言 這方面的資料很多,重覆的寫沒必要,但是最近一直在學習身份驗證和授權相關東東,為了成體系還是寫一篇,主要是從概念上理解identity系統。 參考:https://www.cnblogs.com/r01cn/p/5179506.html 二、概述 幾乎所有系統都包含用戶、角色、許可權、登錄、註 ...
  • 首先我們使用最簡單的模板案例,裡面有一個Counter計數器,你可以在創建模板中找到。 首先需要設置運行調試方式為IIS Express。這意味著,MAC可能不能使用調試。 然後開啟運行而不調試(Ctrl+F5) 按Shift + Alt + D,會出現一個新的頁面。 如果你想用Chrome調試,復 ...
  • 實體映射時,遇到複雜類型,可選擇下述方法處理: NotMapped,跳過映射 在複雜類型上聲明 [Owned],但僅限該複雜類型是全部由簡單值類型組成的 自定義序列化方法 示例: IPInfo使用了owned,對IPEndPoint使用自定義序列化,對VersionInfo使用JSON序列化 @@@... ...
  • .NET Core 3 Web Api Cors fetch 一直 307 Temporary Redirect 繼上一篇 ".net core 3 web api jwt 一直 401" 為添加 所述的坑後, 本次為添加 ,又踩坑了。 自從 .NET Core 2.2 之後,CORS跨域配置代碼發 ...
  • 在前一章已經學習過WPF動畫的第一條規則——每個動畫依賴於一個依賴項屬性。然而,還有另一個限制。為了實現屬性的動態化(換句話說,使用基於時間的方式改變屬性的值),需要有支持相應數據類型的動畫類。例如,Button.Width屬性使用雙精度數據類型。為實現屬性的動態化,需要使用DoubleAnimat ...
  • WPF dotnet core 3.1 基於 `Microsoft.Extensions.Localization` 實現基本的多語言支持 ...
x