天天看點

在JS中通過四種設定事件處理程式的深入了解

所有的JavaScript事件處理程式的作用域是在其定義時的作用域而非調用時的作用域中執行,并且它們能存取那個作用域中的任何一個本地變量。但是HTML标簽屬性注冊處理程式就是一個例外。看下面四中方式:

第一種方式(HTML标簽屬性):

<input type="button" id="btn1" value="測試" onclick="alert(this.id);" />
           

上面的代碼是通過設定HTML标簽屬性為給button 添加了點選事件,當點選button 按鈕時會彈出這個button的id,即btn1。

這種通過HTML屬性來注冊事件處理程式是一個例外。它們被轉換為能存取全局變量的頂級函數而非任何本地變量。由于曆史的原因,它們運作在一個修改後的作用域鍊中。通過HTML屬性定義的事件處理程式能像本地變量一樣使用目标對象、容器對象(form)對象和document對象的屬性。它會被浏覽器轉換為類似如下的代碼:

function (event){
    with(document){
      with(this.form||{}){
        with(this){
         /*具體的事件處理代碼*/
        }
      }
    }    
}
           

關于with的用法,可以自行查閱,這裡後面有文章講解。讀者先自行了解一下。提供一個連接配接(https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/with)

這種方式現在已經不推薦使用。

第二種方式(調用函數)

<input type="button" id="btn2" value="測試" onclick="test()" />
<script type="text/javascript">
    function test(){
      alert(this.id);
    }
</script>
           

這段代碼彈出來的是undefined。

這種設定方式是通過調用全局函數來進行的,這時this指向的是window,而非這個button的調用者,可以通過輸出console.log(this==window);來進行驗證

第三種方式(調用函數)

<input type="button" id="btn3" value="測試" />
<script type="text/javascript">
     var btn3 = document.getElementById("btn3");
                btn3.onclick = function () {
                    alert(this.id);
                };
</script>
           

這段代碼彈出來的是btn3。

這種事件處理程式在事件目标上定義,是以它們作為這個對象的方法來調用(但是下面在IE裡面有個例外)。這就是說在事件處理程式内,this關鍵字指的是事件目标。

當使用addEventListener()注冊時,調用的處理程式使用事件目标作為它們的this值。但是對于還用attachment()注冊的處理程式作為函數調用,它們的this值是全局(window)對象。就是說的第四中方式

第四種方式(通過addEventListener和attachment):

<input type="button" id="btn3" value="測試" onclick="test()" />
  var btn = document.getElementById("btn3");
                var handler = function () {  console.log(this.id); };
                if (btn.addEventListener) {
                    console.log("addEventListener");
                    btn.addEventListener("click", handler, false);
                }
                else if (btn.attachEvent) {//IE9之前的版本
                    console.log("attachEvent");
                    btn.attachEvent("onclick",handler);
                }
           

在IE5-IE8 版本輸出的是undefined。(此時調用的是attachement)

IE9以後的版本輸出的btn3.(修複了上面的問題,增加了通用的addEventListener)。

如果想修複IE5-8裡面的那個問題,可以使用下面的方法。

/*
*target:目标對象,button之類的
*type:"click"字元串事件名稱,無需帶on
*handler:調用的處理程式
*/
function addEvent(target,type,handler){
  if (target.addEventListener) {
                    target.addEventListener(type, handler, false);
                }
                else if (target.attachEvent) {//IE9之前的版本                   
                    btn.attachEvent("on"+type,function(event){
                        return hanlder.call(target,event);//把處理程式作為事件目标的方法調用,更改this指向。
                    });
                }
}
           

繼續閱讀