js函數綁定同時,如何保留代碼執行環境?

來源:互聯網
上載者:User

js函數綁定同時,如何保留代碼執行環境?
 經常寫js的程式員一定不會對下面這段代碼感到陌生。      1  var EventUtil = { 2   3       addHandler : function(element, type, handler){ 4             if(element.addEventListener){ 5                     element.addEventListener(type, handler, false);     6             }else if(element.attachEvent){ 7                      element.attachEvent("on"+type,handler); 8             }else{ 9                      element["on"+type]=handler;10             }11        },12         removeHandler : function(element, type, handler){13             if(element.removeEventListener){14                   element.removeEventListener(type, handler, false);15            }else if(element.detachEvent){16                    element.detachEvent("on"+type, handler);17            }else{18                   element["on"+type]=null;19            }20        }21  } ;    這段代碼可以用跨瀏覽器的方式給元素繫結事件處理函數。   像這樣:  1 var handler = {2     info : "bind me",3     handleClick : function(e){4          alert(this.info);5     }  6 }7 var btn = document.getElementById("mybtn");//一個按鈕8 EventUtil.addHandler( btn, "click", handler.handleClick);    這樣做的話,alert框中顯示的不是“bind me”,而是undefined。這是因為沒有儲存handler.handleClick的環境,即handleClick 中的this並沒有指向handler類。   一般情況下,這樣做也沒有什麼問題。但在某些需要儲存代碼的執行環境的情況下,比如說,事件處理函數、setTimeout()等。在這些情況下,我們可能會需要利用原來執行環境中的某些變數,狀態標識等資訊。   比較容易想到的一種解決方案是使用閉包。   就像這樣:   1  var handler = { 2      info : "bind me", 3      handleClick : function(e){ 4           alert(this.info); 5      }   6  } 7  var btn = document.getElementById("mybtn");//一個按鈕 8  EventUtil.addHandler( btn, "click", function(e){ 9     handler.handleClick(e);10  });     但是,閉包用多了會讓代碼變得難以維護。   於是翻閱資料,發現一個常用的函數 1  function bind(fn, context){2      return function(){3           return fn.apply(context, arguments);4      }5 }   是的,這個函數也使用了閉包,但是這個bind函數還是很強大的,它可以將我們的函數fn,綁定到我們制定的執行環境context中。這個bind函數還是比較好理解的。那麼,可以這樣來使用它。  1   var handler = {2       info : "bind me",3       handleClick : function(e){4            alert(this.info);5       }  6   }7   var btn = document.getElementById("mybtn");//一個按鈕8   EventUtil.addHandler( btn, "click", bind(handler.handleClick, handler));    注意這句 fn.apply(context, arguments); 這樣可以保證事件對象e也傳遞給了fn。   令人慶幸的是,在ECMAScript5中,所有函數都定義一個原生的bind函數,我們可以直接來使用它。  1    var handler = {2        info : "bind me",3        handleClick : function(e){4             alert(this.info+" "+e.type);5        }  6    }7    var btn = document.getElementById("mybtn");//一個按鈕8    EventUtil.addHandler( btn, "click", handler.handleClick.bind(handler));   值得注意的是,IE9+、ff4+,chrome支援這個bind函數。     最近在看一個開源項目的源碼時,發現了一個更好的方法,這個方法不僅能解決上述問題,還能提供更好的事件管理方案。   這個方法就是      addEventListener + handleEvent      首先,我們來看看addEventListener的參數都有哪些,       parameters:     1. type  of type DOMString         The event type for which the user is registering       使用者註冊的事件類型     2.listener of type EventListener         The listener parameter takes an interface implemented by the user which contains the methods to be called when the event occurs.       listener是使用者定義的一個EventListener介面的實現,事件發生時會被調用。(這裡是重點)     3.useCapture of type boolean       定義事件在哪個階段被處理,一般都是false,即在冒泡階段處理事件。              再來看看,EventListener這個介面, 1 // Introduced in DOM Level 2:2 interface EventListener {3   void  handleEvent(in Event evt);4 };    官方對handleEvent的解釋是     This method is called whenever an event occurs of the type for which the EventListener interface was registered.     就是說,在事件發生被處理時,這個函數會被調用,evt就是事件對象。   看來addEventListener的第二個參數,不僅支援傳入一個回呼函數,還可以傳入一個對象,前提是這個對象中實現了handleEvent方法。利用這個特性,可以這樣來使用:  1     var handler = {2         info : "bind me",3         handleEvent : function(e){4              alert(this.info+" "+e.type);5         }  6     }7     var btn = document.getElementById("mybtn");//一個按鈕8     EventUtil.addHandler( btn, "click", handler);      這樣一來,不用當心函數的執行環境被改變。   這個方法還有一個更大的用處就是可以創作一個事件管理中心來更方便,更優雅地管理事件。 像這樣:   1  var handler = { 2          info : "bind me", 3          handleEvent : function(e){ 4               switch(e.type){ 5                      case "mousedown": 6                            this.startHandle(e); 7                            break; 8                      case "mousemove": 9                            this.moveHandle(e);10                            break;11                      case "mouseup":12                            this.endHandle(e);13                            break;14                      default: 15                            //todo16               }17          },18          startHandle:function(e){19               //todo20          },21          moveHandle:function(e){22               //todo23          },24          endHandle:function(e){25               //todo26          }27      }28      var btn = document.getElementById("mybtn");//一個按鈕29      EventUtil.addHandler( btn, "mousedown", handler);    handler類中的handleEvent方法就是一個事件中心,通過事件的類型,來決定採用哪種處理邏輯。是不是很方便。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.