banner
cos

cos

愿热情永存,愿热爱不灭,愿生活无憾
github
tg_channel
bilibili

前端面試之onclick與addEventListener區別詳述

今天面試官問了這麼一個問題:onclickaddEventListener 有哪些區別呢

很好問住了,自己答得不太滿意,下來自己查了查紅寶書第 17 章事件和 MDN,大概了解了是怎麼一回事

上來先把答案擺上:

區別#

addEventListener() 是 W3C DOM 規範中提供的註冊事件監聽器的方法。它的優點包括:

  • 允許給一個事件註冊多個監聽器
    • 特別是在使用 AJAX 庫,JavaScript 模塊,或其他需要第三方庫 / 插件的代碼
  • 提供了一種更精細的手段控制 listener 的觸發階段(可以選擇捕獲或者冒泡)
  • 它對 任何 DOM 元素 都是有效的,而不僅僅只對 HTML 元素有效。
  • 它註冊的事件可以通過 removeEventListener 來移除
    • 也就是說若添加的是匿名事件函數就無法移除了
  • this 的值是觸發事件的元素的引用
    • console.log(e.currentTarget === this) // true

onclick註冊 listener 的舊方法

  • 該方法會替換掉這個元素上所有已存在的 onclick 事件,其他 on 事件也是類似的。
  • 無法精細控制冒泡與否等
  • 移除可通過直接將 onclick 事件替換為 null

兼容性#

addEventListener 在 DOM 2 Events 規範中引入

  • 在 IE 9 之前,必須使用 attachEvent 而不是使用addEventListener
  • attachEvent 方法有個缺點,this 的值會變成 window 對象的引用而不是觸發事件的元素

onclick 是 DOM 0 規範的基本內容

  • 幾乎所有瀏覽器都支持,而且不需要特殊的跨瀏覽器兼容代碼
  • 因此通常這個方法被用於動態地註冊事件處理器,除非必須使用 addEventListener() 才能提供的特殊特性

addEventListener#

EventTarget.addEventListener() 方法將指定的監聽器註冊到 EventTarget 上,當該對象觸發指定的事件時,指定的回調函數就會被執行。 事件目標可以是一個文檔上的元素 Element,DocumentWindow 或者任何其他支持事件的對象 (比如 XMLHttpRequest)

addEventListener()的工作原理是將實現EventListener的函數或對象添加到調用它的EventTarget上的指定事件類型的事件監聽器列表中。

addEventListener 中有三個參數,typelisteneruseCapture,其中第一個參數為 事件類型clickmousemove 等,第二個參數為事件的回調函數,第三個參數為一個指定有關 listener 屬性的可選參數對象,需注意的是:

在舊版本的 DOM 的規定中, addEventListener()的第三個參數是一個布爾值表示是否在捕獲階段調用事件處理程序。隨著時間的推移,很明顯需要更多的選項。與其在方法之中添加更多參數(傳遞可選值將會變得異常複雜),倒不如把第三個參數改為一個包含了各種屬性的對象,這些屬性的值用來被配置刪除事件監聽器的過程。
因為舊版本的瀏覽器(以及一些相對不算古老的)仍然假定第三個參數是布爾值,你需要編寫一些代碼來有效地處理這種情況。你可以對每一個你感興趣的 options 值進行特性檢測。

也就是說,addEventListener 需要額外的代碼來兼容舊瀏覽器,而 onclick 不需要,在要考慮兼容性的場景下就需要好好考慮。

事件中的 this#

addEventListenerthis 的值通常情況下都是觸發事件的元素的引用
- console.log(e.currentTarget === this) // true

但是箭頭函數不然,箭頭函數沒有自己的 this,箭頭函數只會從自己的作用域鏈的上一層繼承 this

onclick#

全局事件處理器(GlobalEventHandlers)的 onclick 屬性,是處理當前元素的 click 事件的事件處理器(event handler)。

當用戶點擊一個元素時,會觸發 click 事件。在每次點擊的整個過程中,click 事件的運行順序在 mousedownmouseup 事件之後。

備註: 當你使用 click 事件去觸發一個動作時,也要考慮向 keydown 事件添加此動作,以便允許不使用鼠標或觸摸屏的用戶進行同樣的操作。
MDN 上講的沒那麼詳細,紅寶書中對 onclick 的描述有很重要的幾點

拓展作用域鏈#

<script> 
function showMessage() { 
    console.log("Hello world!"); 
} 
</script> 
<input type="button" value="Click Me" onclick="showMessage()"/> 

上面以onclick方式指定的事件處理程序會創建一個函數來封裝屬性的值。(但是不建議這麼做,原因結尾有)

這個函數有一個特殊的局部變量 event,其中保存的就是 event 對象

<!-- 輸出"click" --> 
<input type="button" value="Click Me" onclick="console.log(event.type)"> 

有了這個對象,就不用開發者另外定義其他變量,也不用從包裝函數的參數列表中去取了。 在這個函數中,this 值相當於事件的目標元素,如下面的例子所示:

<!-- 輸出"Click Me" --> 
<input type="button" value="Click Me" onclick="console.log(this.value)"> 

這個動態創建的包裝函數還有一個特別有意思的地方,就是其作用域鏈被擴展了。在這個函數中, document 和元素自身的成員都可以被當成局部變量來訪問。而這是通過使用 with 實現的:

function() { 
    with(document) { 
        with(this) { 
        // 屬性值 
        } 
    } 
}

這也是為什麼在 onclick 定義的事件,調用 document 上的事件時可以免去 document 前綴,實際上是它在前面還做了一層包裝。

使用 HTML 指定 onclick 事件處理的一個問題是使 HTML 與 JavaScript 變得強耦合,如果需要修改事件處理程序,則必須在 HTML 和 JavaScript 中都進行修改,不建議使用 HTML 事件處理程序,而建議使用 JavaScript 指定事件處理程序的主要原因。

也就是在 js 中,當真正需要使用 onclick 時,使用如下方式:

let btn = document.getElementById("myBtn"); 
btn.onclick = function(e) { 
    console.log(e.type); // "click" 
};
載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。