Frontend Interview: Detailed Comparison of onclick vs addEventListener

发表于 2022-04-04 21:10 1049 字 6 min read

cos avatar

cos

FE / ACG / 手工 / 深色模式强迫症 / INFP / 兴趣广泛养两只猫的老宅女 / remote

onclick 是 HTML 元素上的旧式事件绑定方式,会覆盖原有事件、无法添加多个监听器、不支持捕获/冒泡控制、兼容性好但灵活性差;而 addEventListener 是 W3C 标准方法,支持多个监听器、捕获与冒泡阶段控制、可动态移除、兼容性稍弱但功能强大且更符合现代开发需求。

This article has been machine-translated from Chinese. The translation may contain inaccuracies or awkward phrasing. If in doubt, please refer to the original Chinese version.

Today the interviewer asked this question: What are the differences between onclick and addEventListener?

Great question — it stumped me. I wasn’t satisfied with my answer, so afterward I looked it up in “JavaScript: The Definitive Guide” (the “Red Book”) Chapter 17 on Events and MDN. Here’s what I found.

Let me start with the answer:

Differences

addEventListener() is the method specified in the W3C DOM specification for registering event listeners. Its advantages include:

  • Allows registering multiple listeners for a single event
    • Particularly useful when working with AJAX libraries, JavaScript modules, or other code that requires third-party libraries/plugins
  • Provides a more fine-grained way to control the triggering phase of listener (you can choose capturing or bubbling)
  • It works on any DOM element, not just HTML elements.
  • Events registered with it can be removed via removeEventListener
    • This also means anonymous event functions cannot be removed
  • The value of this is a reference to the element that triggered the event
    • console.log(e.currentTarget === this) // true

On the other hand, onclick is the old way of registering listeners

  • This method will replace all existing onclick events on the element, and other on-events work similarly.
  • Cannot provide fine-grained control over bubbling, etc.
  • Removal can be done by directly replacing the onclick event with null

Compatibility

addEventListener was introduced in the DOM 2 Events specification

  • Before IE 9, attachEvent had to be used instead of addEventListener
  • attachEvent has a drawback: the value of this becomes a reference to the window object rather than the element that triggered the event

Meanwhile, onclick is basic content from the DOM 0 specification

  • Almost all browsers support it, and it doesn’t require special cross-browser compatibility code
  • Therefore, this method is often used to dynamically register event handlers, unless the special features that only addEventListener() can provide are needed

addEventListener

EventTarget.addEventListener() registers the specified listener on the EventTarget. When the object triggers the specified event, the specified callback function is executed. The event target can be an Element in the document, a Document, a Window, or any other object that supports events (such as XMLHttpRequest).

addEventListener() works by adding a function or object that implements EventListener to the list of event listeners for the specified event type on the EventTarget on which it is called.

addEventListener takes three parameters: type, listener, and useCapture. The first parameter is the event type (e.g., click, mousemove), the second is the callback function for the event, and the third is an optional parameter object specifying properties about the listener. Important to note:

In older versions of the DOM specification, the third parameter of addEventListener() was a boolean indicating whether to call the event handler during the capture phase. Over time, it became clear that more options were needed. Rather than adding more parameters to the method (which would make passing optional values extremely complicated), the third parameter was changed to an object containing various properties whose values configure the event listener removal process.
Since older browsers (and some relatively recent ones) still assume the third parameter is a boolean, you need to write code to effectively handle this situation. You can do feature detection for each options value you’re interested in.

In other words, addEventListener requires additional code for compatibility with older browsers, while onclick does not. This needs careful consideration in scenarios where compatibility matters.

this in Events

In addEventListener, the value of this is typically a reference to the element that triggered the event — console.log(e.currentTarget === this) // true

However, arrow functions are different. Arrow functions don’t have their own this — they inherit this from the upper level of their scope chain.

onclick

The onclick property of the GlobalEventHandlers is the event handler for the click event of the current element.

When a user clicks an element, a click event is triggered. The order of the click event in the entire click process comes after the mousedown and mouseup events.

Note: When using the click event to trigger an action, also consider adding this action to the keydown event to allow users who don’t use a mouse or touchscreen to perform the same action. The MDN documentation doesn’t go into much detail, but the Red Book has several important points about onclick.

Extended Scope Chain

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

An event handler specified via onclick in this way creates a function that wraps the attribute’s value. (This approach is not recommended, reasons explained at the end.)

This function has a special local variable event, which holds the event object:

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

With this object, developers don’t need to define additional variables or extract them from the wrapper function’s parameter list. In this function, the this value is equivalent to the event’s target element, as shown below:

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

A particularly interesting aspect of this dynamically created wrapper function is that its scope chain is extended. In this function, document and the element’s own members can be accessed as local variables. This is achieved using with:

function() {
    with(document) {
        with(this) {
        // property value
        }
    }
}

This is also why events defined with onclick can call events on document without the document prefix — there’s actually an additional layer of wrapping in front.

One problem with using HTML to specify onclick event handlers is that it creates tight coupling between HTML and JavaScript. If you need to modify the event handler, you must make changes in both HTML and JavaScript. This is the main reason why HTML event handlers are discouraged, and JavaScript-specified event handlers are recommended instead.

So in JavaScript, when you truly need to use onclick, use the following approach:

let btn = document.getElementById('myBtn');
btn.onclick = function (e) {
  console.log(e.type); // "click"
};

喜欢的话,留下你的评论吧~

© 2020 - 2026 cos @cosine
Powered by theme astro-koharu · Inspired by Shoka