成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

addEvent.js源碼解析

RaoMeng / 1097人閱讀

摘要:在看源碼時(shí),發(fā)現(xiàn)了這段注釋源碼行的庫(kù)為的事件綁定提供了很多想法,我們就來(lái)看下年的。五內(nèi)存泄漏簡(jiǎn)單說(shuō)只綁定一次,只綁定一次。并通過(guò)來(lái)為每一個(gè)定一個(gè),然后依次添加進(jìn)中,并通過(guò)執(zhí)行如果一直調(diào)用來(lái)綁定事件的話,內(nèi)存開銷會(huì)很大。最后完整代碼請(qǐng)看完

前言:
看兩三遍即可。

在看 jQuery 源碼時(shí),發(fā)現(xiàn)了這段注釋:

  //源碼5235行
  /*
 * Helper functions for managing events -- not part of the public interface.
 * Props to Dean Edwards" addEvent library for many of the ideas.
 */
  jQuery.event = { }

Dean Edwards 的 addEvent.js 庫(kù)為 jQuery 的事件綁定提供了很多想法,我們就來(lái)看下 2005 年的 addEvent.js 。

〇、先復(fù)習(xí)下 Object 的內(nèi)存地址指向的知識(shí)

  let a={ }
  let b=a
  b[0]="111"
  
  console.log(a,"a55") //{0:"111"}

b 改變屬性,a 也會(huì)改變,因?yàn)?b 與 a 指向同一地址(b=a)

一、addEvent()
作用:
為目標(biāo)元素綁定事件(如 click)

源碼:

  //addEvent即為DOM元素綁定事件

  // a counter used to create unique IDs
  //為每一個(gè)事件添加唯一的id
  addEvent.guid = 1;

  function addEvent(element, type, handler) {
    // assign each event handler a unique ID
    //如果用戶自定義的回調(diào)函數(shù)沒有$$guid的話,
    //為每個(gè)handler添加唯一的id
    if (!handler.$$guid) handler.$$guid = addEvent.guid++;
    // create a hash table of event types for the element
    //為目標(biāo)元素添加events屬性
    if (!element.events) element.events = {};
    // create a hash table of event handlers for each element/event pair
    //events是目標(biāo)元素綁定的事件的集合
    //第一次使用addEvent綁定往往是undefined
    let handlers = element.events[type];
    if (!handlers) {
      handlers = element.events[type] = {};
      // store the existing event handler (if there is one)
      //handlers的0屬性作為目標(biāo)元素的原生綁定事件
      if (element["on" + type]) {
        handlers[0] = element["on" + type];
      }
    }
    // store the event handler in the hash table
    //將每次綁定的事件保存到handler的id屬性中
    handlers[handler.$$guid] = handler;

    // assign a global event handler to do all the work
    //為目標(biāo)元素的原生事件綁定處理程序(handleEvent)
    element["on" + type] = handleEvent;
  }

解析:
注意let handlers = element.events[type],handlers 與 element.events[type] 指向同一地址,接下來(lái)都是對(duì) handlers 進(jìn)行操作,實(shí)際上也就是對(duì) element.events 進(jìn)行操作

關(guān)鍵!
addEvent 的目的是讓目標(biāo)元素的結(jié)構(gòu)如下:

element:{
  //依次執(zhí)行了 click 對(duì)象里的每個(gè) handler
  onclick:handleEvent(MouseEvent)
  events:{
    click:{
      // 如果先onclick了,就會(huì)在這里
      // 0 : onclick(也就是 function (e) {console.log("原生點(diǎn)擊了one")})
      1 : handler(也就是 function(){console.log("點(diǎn)擊了one")}  )
      2 : handler ( xxx )
      3 : ...
     .. : ...    
    },
    foucus:{
      
    }, 
    ..... :{
    
    }

  }
}

注意里面的注釋。
(1)可以看到通過(guò) addEvent 綁定的"click"事件并不是真的綁定在 element 上,而是把綁定的事件處理程序(handler)都放到了 element 的 events 上,即綁定事件和目標(biāo)元素的分離

(2)由 handleEvent 來(lái)統(tǒng)一執(zhí)行 click 事件

二、handleEvent()
作用:
執(zhí)行事件的處理程序

源碼:

  //執(zhí)行事件的處理程序
  function handleEvent(event) {
    // grab the event object (IE uses a global event object)
    console.log(event,"event55")
    //event即MouseEvent,原生的鼠標(biāo)事件集合
    event = event || window.event;
    // get a reference to the hash table of event handlers
    //找到相同事件的處理程序
    //注意這個(gè)this,指的是目標(biāo)元素
    //找到handlers集合
    let handlers = this.events[event.type];
    // execute each event handler

    //依次執(zhí)行事件的處理程序
    for (let i in handlers) {
      this.$$handleEvent = handlers[i];
      this.$$handleEvent(event);
    }
  }

解析:
(1)看到上面的關(guān)鍵,再看 handleEvent 就簡(jiǎn)單地多,就是把 element->events->click 里的事件處理程序都執(zhí)行下

(2)主要看for 里面,多了個(gè)handlers 和 handleEvent,我感覺是多余的(不知道下面說(shuō)的對(duì)不對(duì),因?yàn)橄氲搅酥袑W(xué)解數(shù)學(xué)題,當(dāng)你覺得題干中的條件你用不到時(shí),往往是自己想錯(cuò)了),因?yàn)橹苯舆@么寫就好了?。?/p>

寫法一:

  function handleEvent(event) {
    event = event || window.event;
    for (let i in this.events[event.type]) {
      this.events[event.type][i](event)
    }
 }

寫法二:

  function handleEvent(event) {
    event = event || window.event;
    let handlers = this.events[event.type];
    for (let i in handlers) {
      handlers[i].call(this,event)
    }
 }

根據(jù)this誰(shuí)調(diào)用的,this就是誰(shuí)的原則,那么handleEvent thiselement["on"+type],即element.onclick在調(diào)用handleEvent 方法,既然是element的屬性onclick在調(diào)用的話,那么執(zhí)行的上下文就是element,thiselement

Dean Edwards用this.$$handleEvent來(lái)執(zhí)行handler,目的也是保證正確的作用域,即this

三、removeEvent

  //移除監(jiān)聽事件
  function removeEvent(element, type, handler) {
    // delete the event handler from the hash table
    console.log(handler,"handler52")
    if (element.events && element.events[type]) {
      delete element.events[type][handler.$$guid];
    }
  }

注意:不把自定義事件包成一個(gè)變量,是移除不了監(jiān)聽事件的:

  let one=document.querySelector("#one")
  addEvent(one,"click",function () {
    console.log("點(diǎn)擊了one")
  })
  removeEvent(one,"click",function () {
    console.log("點(diǎn)擊了one")
  })

寫成這樣才可以:

  let one=document.querySelector("#one")
  let handler=function () {
    console.log("點(diǎn)擊了one")
  }
  addEvent(one,"click",handler)
  removeEvent(one,"click",handler)

四、實(shí)驗(yàn)

干我
let one=document.querySelector("#one") one.onclick=function (e) { console.log("原生點(diǎn)擊了one") } addEvent(one,"click",function () { console.log("點(diǎn)擊了one") })

輸出:原生點(diǎn)擊了one 點(diǎn)擊了one

干我
let one=document.querySelector("#one") addEvent(one,"click",function () { console.log("點(diǎn)擊了one") }) one.onclick=function (e) { console.log("原生點(diǎn)擊了one") }

輸出:原生點(diǎn)擊了one ,原因是后面的 one.onclick 覆蓋了 addEvent() 里的事件綁定

當(dāng)然 jQuery 是都會(huì)觸發(fā)的。

五、內(nèi)存泄漏
簡(jiǎn)單說(shuō):
element只綁定一次onclick,只綁定一次events。
并通過(guò)guid來(lái)為每一個(gè)handler定一個(gè)id,然后依次添加進(jìn)events.click中,并通過(guò)onclick執(zhí)行

如果一直調(diào)用onclick來(lái)綁定事件的話,內(nèi)存開銷會(huì)很大。

最后:
完整代碼請(qǐng)看https://github.com/AttackXiaoJinJin/jQueryExplain/blob/master/addEvent.js.html

(完)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/104420.html

相關(guān)文章

  • Flink Metrics 源碼解析

    摘要:有如下模塊源碼解析源碼解析源碼解析源碼解析源碼解析源碼解析源碼解析源碼解析源碼解析使用和監(jiān)控和博客從到學(xué)習(xí)介紹從到學(xué)習(xí)上搭建環(huán)境并構(gòu)建運(yùn)行簡(jiǎn)單程序入門從到學(xué)習(xí)配置文件詳解從到學(xué)習(xí)介紹從到學(xué)習(xí)如何自 Flink Metrics 有如下模塊: Flink Metrics 源碼解析 —— Flink-metrics-core Flink Metrics 源碼解析 —— Flink-metr...

    sshe 評(píng)論0 收藏0
  • Flink 源碼解析 —— 深度解析 Flink Checkpoint 機(jī)制

    摘要:機(jī)制博客從到學(xué)習(xí)介紹從到學(xué)習(xí)上搭建環(huán)境并構(gòu)建運(yùn)行簡(jiǎn)單程序入門從到學(xué)習(xí)配置文件詳解從到學(xué)習(xí)介紹從到學(xué)習(xí)如何自定義從到學(xué)習(xí)介紹從到學(xué)習(xí)如何自定義從到學(xué)習(xí)轉(zhuǎn)換從到學(xué)習(xí)介紹中的從到學(xué)習(xí)中的幾種詳解從到學(xué)習(xí)讀取數(shù)據(jù)寫入到從到學(xué)習(xí)項(xiàng)目如何運(yùn)行從 Flink Checkpoint 機(jī)制 https://t.zsxq.com/ynQNbeM 博客 1、Flink 從0到1學(xué)習(xí) —— Apache Fl...

    0x584a 評(píng)論0 收藏0
  • Flink 源碼解析 —— 深度解析 Flink 序列化機(jī)制

    摘要:序列化機(jī)制博客從到學(xué)習(xí)介紹從到學(xué)習(xí)上搭建環(huán)境并構(gòu)建運(yùn)行簡(jiǎn)單程序入門從到學(xué)習(xí)配置文件詳解從到學(xué)習(xí)介紹從到學(xué)習(xí)如何自定義從到學(xué)習(xí)介紹從到學(xué)習(xí)如何自定義從到學(xué)習(xí)轉(zhuǎn)換從到學(xué)習(xí)介紹中的從到學(xué)習(xí)中的幾種詳解從到學(xué)習(xí)讀取數(shù)據(jù)寫入到從到學(xué)習(xí)項(xiàng)目如何 Flink 序列化機(jī)制 https://t.zsxq.com/JaQfeMf 博客 1、Flink 從0到1學(xué)習(xí) —— Apache Flink 介紹 2...

    y1chuan 評(píng)論0 收藏0
  • Flink Clients 源碼解析

    摘要:模塊中的類結(jié)構(gòu)如下博客從到學(xué)習(xí)介紹從到學(xué)習(xí)上搭建環(huán)境并構(gòu)建運(yùn)行簡(jiǎn)單程序入門從到學(xué)習(xí)配置文件詳解從到學(xué)習(xí)介紹從到學(xué)習(xí)如何自定義從到學(xué)習(xí)介紹從到學(xué)習(xí)如何自定義從到學(xué)習(xí)轉(zhuǎn)換從到學(xué)習(xí)介紹中的從到學(xué)習(xí)中的幾種詳解從到學(xué)習(xí)讀取數(shù)據(jù)寫入到從到學(xué) Flink-Client 模塊中的類結(jié)構(gòu)如下: https://t.zsxq.com/IMzNZjY showImg(https://segmentfau...

    xiao7cn 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<