I’m having trouble understanding how the this keyword works in different JavaScript event scenarios. Here’s what I’m seeing:
<tr><td><button onclick="javascript:showAlert(this)">Remove</button></td></tr>
<ul><li onclick="showAlert(this)">Item</li></ul>
When I click the button element, this refers to the window object. But when I click the list item, this points to the HTMLLIElement itself. This seems inconsistent to me. Can someone explain why the context of this changes between these two situations? I expected both elements to behave the same way since they’re both using onclick handlers. What’s causing this difference in behavior?
This totally caught me off guard during a project migration last year. The javascript: protocol creates a different execution context because it was originally designed for hyperlinks, not event handlers. When the browser sees javascript: in an onclick attribute, it processes the code as if it’s running from a link’s href attribute, which defaults to the global window context. Your button handler runs in isolation from the DOM element that triggered it. I spent hours debugging this exact behavior until I figured out that inline event handlers without the protocol prefix keep their natural binding to the triggering element. Modern browsers handle direct function calls in onclick by automatically binding the element as the context, which is why your list item works as expected.
The difference is how the browser handles javascript: protocol versus a direct function call. When you use onclick="javascript:showAlert(this)", the browser treats it as a URL and executes the code in the global scope, making this refer to the window object. In contrast, onclick="showAlert(this)" calls the function directly in the context of the current element, hence this refers to the clicked element. I encountered this issue in legacy code a couple of years ago. The javascript: prefix is unnecessary and leads to these scope inconsistencies. Removing it from your button handler will ensure both elements behave uniformly.
yeah, same thing tripped me up when i started. the javascript: protocol runs your code in global context instead of element context. just remove the javascript: part from your button and it’ll work like the li element. super common gotcha.