欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

最佳的addEvent事件綁定是怎樣誕生的

 更新時間:2011年10月24日 00:55:16   投稿:mdxy-dxy  
IE的 JScript 存在內(nèi)存泄露的bug 想必大家都清楚或者有耳聞了。這是由于IE的內(nèi)存回收管理器的一個設(shè)計錯誤導(dǎo)致的

當(dāng)我們編寫腳本的時候創(chuàng)建了交叉引用,例如如下代碼:

window.onload = function() {
  var x = document.getElementsByTagName('H3');
  for (var i = 0; i < x.length; i++) {
    x[i].onclick = openClose;
    x[i].relatedElement = x[i].nextSibling; // simplified situation 
    x[i].relatedElement.relatedElement = x[i];
  }
}

或者在函數(shù)中使用腳本語言最常見的閉句Closures的時候,IE都無法回收內(nèi)存。而閉句在給DOM對象注冊事件處理器(event handler)的時候最為常用。Novemberborn提供了一些example可以讓你運行并切實感受到這個bug。
我最喜愛的QuirkMode 去年初意識到這個bug存在巨大隱患,覺得有必要呼吁廣大web開發(fā)者關(guān)注并竭力避免這個問題,于是舉辦了一個慈善邀請賽,鼓勵大家提交各自 addEvent/removeEvent 方案。并終于在去年10月下旬宣布了他們認(rèn)為的勝利者:John Resig,讓John贏得勝利的代碼如下:

function addEvent(obj, type, fn) {
  if (obj.attachEvent) {
    obj['e' + type + fn] = fn;
    obj[type + fn] = function() {
      obj['e' + type + fn](window.event);
    }
    obj.attachEvent('on' + type, obj[type + fn]);
  } else obj.addEventListener(type, fn, false);
}
function removeEvent(obj, type, fn) {
  if (obj.detachEvent) {
    obj.detachEvent('on' + type, obj[type + fn]);
    obj[type + fn] = null;
  } else obj.removeEventListener(type, fn, false);
}

QuirkMode 對選擇John為勝利者的解釋概括來說就是以上代碼最簡潔有效,在避免內(nèi)存問題的同時還巧妙的保證了this關(guān)鍵字在ie的attachEvent中能正常工作。缺點當(dāng)然還是存在:

不支持 Netscape 4 和 Explorer 5 Mac。(有可能國內(nèi)的程序員會嗤之以鼻,但國外很強(qiáng)調(diào)廣泛的兼容性)
在 removeEvent 中遺漏了remove obj["e"+type+fn]。
總之不管怎么說,簡單取勝。
結(jié)果一出,眾多參賽與評論者不服氣,很快又挑出了John的代碼的幾處毛?。?

addEvent中本身就使用了閉句,所以沒有根本解決IE內(nèi)存泄露的問題。
沒有解決同類型的事件可能被重復(fù)注冊而被IE重復(fù)執(zhí)行的問題。
幾個高手于是提出了改進(jìn)性的方案:

/* 
Original idea by John Resig 
Tweaked by Scott Andrew LePera, Dean Edwards and Peter-Paul Koch 
Fixed for IE by Tino Zijdel (crisp) 
Note that in IE this will cause memory leaks and still doesn't quite function the same as in browsers that do support the W3C event model: 
- event execution order is not the same (LIFO in IE against FIFO) 
- functions attached to the same event on the same element multiple times will also get executed multiple times in IE 
*/
function addEvent(obj, type, fn) {
  if (obj.addEventListener) obj.addEventListener(type, fn, false);
  else if (obj.attachEvent) {
    obj["e" + type + fn] = fn;
    obj.attachEvent("on" + type,
    function() {
      obj["e" + type + fn]();
    });
  }
}
function removeEvent(obj, type, fn) {
  if (obj.removeEventListener) obj.removeEventListener(type, fn, false);
  else if (obj.detachEvent) {
    obj.detachEvent("on" + type, obj["e" + type + fn]);
    obj["e" + type + fn] = null;
  }
}

很明顯,雖然修正了John代碼的一些不足。但內(nèi)存泄露依然存在,部分瀏覽器依然不支持,還是無法避免ie重復(fù)注冊。另外根據(jù)注釋:當(dāng)在同一個對象上注冊多個事件處理器的時候,IE與其他瀏覽器的執(zhí)行順序是不同的,這又是一個隱患。

幾天之后,一個被認(rèn)為最嚴(yán)謹(jǐn)?shù)姆桨赣蒁ean Edwards 提出。Dean他的方案與眾不同:

不執(zhí)行對象檢測(Object detection)
沒有調(diào)用 addeventListener/attachEvent 方法
保持this關(guān)鍵字的運行于正確的上下文環(huán)境
正確傳遞 event 對象參數(shù)
完全跨瀏覽器至此(包括IE4和NS4)
不存在內(nèi)存泄露

Dean的代碼如下:

// written by Dean Edwards, 2005 
// http://dean.edwards.name/function ;addEvent(element, type, handler) { 
// assign each event handler a unique ID 
// 為事件處理函數(shù)設(shè)定一個唯一值 
if (!handler.$$guid) handler.$$guid = addEvent.guid++;
// create a hash table of event types for the element 
if (!element.events) element.events = {};
// create a hash table of event handlers for each element/event pair 
var handlers = element.events[type];
if (!handlers) {
  handlers = element.events[type] = {};
  // store the existing event handler (if there is one) 
  // 如果對象已經(jīng)注冊有事件處理,那么要保留下來,并保存為第一個 
  if (element["on" + type]) {
    handlers[0] = element["on" + type];
  }
}
// store the event handler in the hash table 
handlers[handler.$$guid] = handler;
// assign a global event handler to do all the work 
// 指派一個全局函數(shù)做統(tǒng)一的事件處理,同時避免了反復(fù)注冊 
element["on" + type] = handleEvent;
};
// a counter used to create unique IDs 
addEvent.guid = 1;
function removeEvent(element, type, handler) {
  // delete the event handler from the hash table 
  if (element.events && element.events[type]) {
    delete element.events[type][handler.$$guid];
  }
};
function handleEvent(event) {
  // grab the event object (IE uses a global event object) 
  event = event || window.event;
  // get a reference to the hash table of event handlers 
  // 這里的 this 隨 handlerEvent function 被觸發(fā)的source element 變化而變化 
  var handlers = this.events[event.type];
  // execute each event handler 
  for (var i in handlers) {
    //這樣寫才能保證注冊的事件處理函數(shù)中的 this 得到正確的引用,直接handlers[i]()是不行的 
    this.$$handleEvent = handlers[i];
    this.$$handleEvent(event);
  }
};

這段代碼相比之前就大了不少了,不過確實很精妙??墒沁@段代碼卻引入了其他的問題,比如無法處理事件處理函數(shù)的返回值,for..in循環(huán)可能因為 (Object.prototype)的錯誤應(yīng)用而中斷等等...很快Dean推出一個"updated version"。

要做到最好真的好辛苦。

目前似乎Dean的最終版本是最全面的解決方案。不過就我個人意見,感覺有些吹毛求疵了。盡量使用瀏覽器本身的實現(xiàn)和保持簡單是我一貫堅持的主張。但洋人這種嚴(yán)謹(jǐn)?shù)膽B(tài)度,還是讓我深深敬佩。

相關(guān)文章

  • 150行代碼帶你實現(xiàn)微信小程序中的數(shù)據(jù)偵聽

    150行代碼帶你實現(xiàn)微信小程序中的數(shù)據(jù)偵聽

    在這篇文章中, 我將用150行代碼, 手把手帶你打造一個小程序也可以使用的偵聽器,感興趣的朋友跟隨小編一起看看吧
    2019-05-05
  • TypeScript泛型參數(shù)默認(rèn)類型和新的strict編譯選項

    TypeScript泛型參數(shù)默認(rèn)類型和新的strict編譯選項

    這篇文章主要介紹了TypeScript泛型參數(shù)默認(rèn)類型和新的strict編譯選項,對TypeScript感興趣的同學(xué),可以參考下
    2021-05-05
  • JavaScript數(shù)組every方法的應(yīng)用場景實例

    JavaScript數(shù)組every方法的應(yīng)用場景實例

    every方法確定數(shù)組中的每一項的結(jié)果都滿足所寫的條件的時候,就會返回true,否則返回false,這篇文章主要給大家介紹了關(guān)于JavaScript數(shù)組every方法應(yīng)用場景的相關(guān)資料,需要的朋友可以參考下
    2022-12-12
  • 計算黃金分割的javascript代碼

    計算黃金分割的javascript代碼

    計算黃金分割的javascript代碼...
    2007-07-07
  • JS實現(xiàn)兼容性較好的隨屏滾動效果

    JS實現(xiàn)兼容性較好的隨屏滾動效果

    這篇文章主要介紹了JS實現(xiàn)兼容性較好的隨屏滾動效果,演示了固定位置顯示和隨屏滾動兩種效果的實現(xiàn)方法,涉及css樣式的設(shè)置與結(jié)合時間函數(shù)遞歸調(diào)用實現(xiàn)滾屏的技巧,需要的朋友可以參考下
    2015-11-11
  • 淺談JS使用[ ]來訪問對象屬性

    淺談JS使用[ ]來訪問對象屬性

    下面小編就為大家?guī)硪黄獪\談JS使用[ ]來訪問對象屬性。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-09-09
  • js實現(xiàn)ajax的用戶簡單登入功能

    js實現(xiàn)ajax的用戶簡單登入功能

    這篇文章主要為大家詳細(xì)介紹了js實現(xiàn)ajax的用戶簡單登入功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-06-06
  • Weex開發(fā)之地圖篇的具體使用

    Weex開發(fā)之地圖篇的具體使用

    這篇文章主要介紹了Weex開發(fā)之地圖篇的具體使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • 詳解通用webpack多頁面自動導(dǎo)入方案

    詳解通用webpack多頁面自動導(dǎo)入方案

    本文主要介紹了通用webpack多頁面自動導(dǎo)入方案,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • 前端插件之Bootstrap Dual Listbox使用教程

    前端插件之Bootstrap Dual Listbox使用教程

    這篇文章主要介紹了前端插件之Bootstrap Dual Listbox使用教程,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價值 ,需要的朋友可以參考下
    2019-07-07

最新評論