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

最佳的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可以讓你運(yùn)行并切實(shí)感受到這個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中能正常工作。缺點(diǎn)當(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)鍵字的運(yù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í)很精妙??墒沁@段代碼卻引入了其他的問題,比如無法處理事件處理函數(shù)的返回值,for..in循環(huán)可能因?yàn)?(Object.prototype)的錯誤應(yīng)用而中斷等等...很快Dean推出一個"updated version"。

要做到最好真的好辛苦。

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

相關(guān)文章

  • JS 頁面計時器示例代碼

    JS 頁面計時器示例代碼

    計時器效果想必大家都見到過吧,其實(shí)使用js可以很輕松的實(shí)現(xiàn),下面有個不錯的示例,感興趣的朋友可以參考下
    2013-10-10
  • 使用js實(shí)現(xiàn)雪花飄落效果

    使用js實(shí)現(xiàn)雪花飄落效果

    以下是對使用js實(shí)現(xiàn)雪花飄落的效果進(jìn)行了介紹。需要的朋友可以 過來參考下
    2013-08-08
  • form.submit()不能提交表單的原因分析

    form.submit()不能提交表單的原因分析

    這篇文章主要分析了form.submit()不能提交表單的原因,需要的朋友可以參考下
    2014-10-10
  • layer子層給父層頁面元素賦值,以達(dá)到向父層頁面?zhèn)髦档男Ч麑?shí)例

    layer子層給父層頁面元素賦值,以達(dá)到向父層頁面?zhèn)髦档男Ч麑?shí)例

    下面小編就為大家?guī)硪黄猯ayer子層給父層頁面元素賦值,以達(dá)到向父層頁面?zhèn)髦档男Ч麑?shí)例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • 深入理解JavaScript柯里化的概念和原理

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

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

    Javascript&DHTML基礎(chǔ)知識

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

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

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

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

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

    Bootstrap導(dǎo)航條學(xué)習(xí)使用(二)

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

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

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

最新評論

隆安县| 阿图什市| 元江| 新野县| 礼泉县| 武宣县| 化州市| 修武县| 固始县| 怀化市| 四会市| 尚志市| 漾濞| 叙永县| 青神县| 巨野县| 额尔古纳市| 江永县| 乌拉特后旗| 平泉县| 湖口县| 托克托县| 邯郸市| 宜君县| 祁东县| 库伦旗| 贺州市| 清水河县| 阆中市| 潞城市| 禹州市| 富民县| 凉城县| 上饶县| 武隆县| 陇西县| 兴安盟| 西丰县| 诏安县| 托里县| 陇南市|