最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

當我們編寫腳本的時候創(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月下旬宣布了他們認為的勝利者: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中能正常工作。缺點當然還是存在:

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

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

/* 
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ù)注釋:當在同一個對象上注冊多個事件處理器的時候,IE與其他瀏覽器的執(zhí)行順序是不同的,這又是一個隱患。

幾天之后,一個被認為最嚴謹?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)和保持簡單是我一貫堅持的主張。但洋人這種嚴謹?shù)膽B(tài)度,還是讓我深深敬佩。

相關(guān)文章

  • 深入理解JavaScript柯里化的概念和原理

    深入理解JavaScript柯里化的概念和原理

    在JS編程中, 函數(shù)是一等公民, 具備了強大的靈活性和復(fù)用性,而柯里化作為一種高階技術(shù), 可以進一步提升函數(shù)的復(fù)用性和靈活性,在本篇博客中, 我們將深入探討 JS 中柯里化的概念和原理, 并了解其在實際開發(fā)中的應(yīng)用場景,需要的朋友可以參考下
    2023-06-06
  • Javascript&DHTML基礎(chǔ)知識

    Javascript&DHTML基礎(chǔ)知識

    首先請下載JScript.chm這本手冊,無論新手老手,有一本手冊是免不了的,特別是對于新手,如果你沒有空翻犀牛書,那么這本手冊將是你了解這門語言的首選。下面所講的大多數(shù),手冊上可以沒有提及,或提及很少的內(nèi)容。
    2008-07-07
  • Jjcarousellite 實現(xiàn)圖片列表滾動的簡單實例

    Jjcarousellite 實現(xiàn)圖片列表滾動的簡單實例

    這篇文章主要介紹了Jjcarousellite 實現(xiàn)圖片列表滾動的簡單實例,有需要的朋友可以參考一下
    2013-11-11
  • Ionic如何創(chuàng)建APP項目

    Ionic如何創(chuàng)建APP項目

    這篇文章主要介紹Ionic如何創(chuàng)建APP項目的相關(guān)資料,非常不錯具有參考借鑒價值,需要的朋友可以參考下
    2016-06-06
  • Bootstrap導(dǎo)航條學習使用(二)

    Bootstrap導(dǎo)航條學習使用(二)

    這篇文章主要為大家詳細介紹了Bootstrap導(dǎo)航條的使用方法第二篇,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-02-02
  • JavaScript?賦值,淺復(fù)制和深復(fù)制的區(qū)別

    JavaScript?賦值,淺復(fù)制和深復(fù)制的區(qū)別

    這篇文章主要介紹了JavaScript?賦值,淺復(fù)制和深復(fù)制的區(qū)別,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-05-05
  • 最新評論

    古田县| 滦平县| 贵州省| 台东市| 镇巴县| 桐柏县| 汤原县| 怀来县| 通州区| 溆浦县| 伊春市| 镇坪县| 应城市| 互助| 乌审旗| 苏州市| 体育| 疏附县| 军事| 肇东市| 孝义市| 新泰市| 新邵县| 新源县| 康马县| 滨州市| 林州市| 阆中市| 宝丰县| 翁牛特旗| 巨鹿县| 固镇县| 三门峡市| 奈曼旗| 石河子市| 陇南市| 册亨县| 邵东县| 温泉县| 吉林市| 连平县|