JavaScript ‘this’ and Event Handlers

Tweet

If there’s one reason to rely on a JavaScript library such as jQuery, it’s event handling. Most libraries abstract events into a uniform set of objects and handlers which work in most modern browsers. But we don’t need a library — we’re hardcore JavaScript developers!

Events 101

Without events and handlers, we would never be able to create slick client-side web applications. Events allow JavaScript to detect when a certain action has been performed by the user, e.g. hovering over an element, clicking a link, scrolling the page, resizing the window, dragging an object or any other activity.

Your JavaScript code can register a handler function which is triggered when a particular event occurs. Most browsers pass a single object to the function which contains information about the event, i.e. what keys were pressed, the position of the cursor, etc. It’s then possible to take certain actions such as animating an element, making an Ajax call, or preventing the browser’s default action.

In addition, ‘this’ may be set. You can normally expect it to be the element which fired the event, but that’s not always the case…

Inline events

These were the first event handlers browsers supported:


<p><a id="link" href="#" onclick="EventHandler();">click me</a></p>

<script>
function EventHandler() {
	console.log(this);
}
</script>

In this case, we’re simply running a function when the onclick event occurs and ‘this’ will be the global window object. We can make a minor change to our inline handler so the <a> element is passed:


<p><a id="link" href="#" onclick="return EventHandler(this);">click me</a></p>

Note that we’ve also added ‘return’. If our EventHandler returns false, the click event will be canceled.

important: Never use inline event handlers!

I’ve said this before but it needs repeating. Inline event handlers are limited, clunky, and can bulk up your HTML code. They cause maintenance complications since the invoking of the event and its handler are defined in different places. Finally, script tags must be placed at the top of your HTML rather than the bottom because an event could be called as the page is loading.

Traditional DOM0 events

Here’s our example using traditional event handling:


<p><a id="link" href="#">click me</a></p>

<script>
var link = document.getElementById("link");
link.onclick = EventHandler;

function EventHandler() {
	console.log(this.id);
}
</script>

In EventHandler(), every browser sets ‘this’ to the element which fired the event — our anchor tag. It’s reliable but has a major drawback: we can only assign a single handler for each event type.

note: Drop the parenthesis!

Be careful not to use link.onclick = EventHandler(); — EventHandler will be run immediately and the value returned (undefined) will be assigned to the onclick property of the #link node. It may not throw an error, but your handler will never be called when the click event occurs.

Modern DOM2 events

Finally, we have modern event handling which allows multiple handlers to be specified for the same event. Unfortunately, Microsoft and the W3C had a few differences of opinion with regard to their implementation and only IE9 supports addEventListener(). We can, however, use a little object detection to create a cross-browser event-attaching function which works in all browsers:


<p><a id="link" href="#">click me</a></p>

<script>
var link = document.getElementById("link");
AttachEvent(link, "click", EventHandler);

function AttachEvent(element, type, handler) {
	if (element.addEventListener) element.addEventListener(type, handler, false);
	else element.attachEvent("on"+type, handler);
}

function EventHandler(e) {
	console.log(this);
}
</script>

As with DOM0, all browsers set ‘this’ to the element which fired the event … except one. Internet Explorer 8.0 and below only reference the event handler so ‘this’ is always the global window object.

Fortunately we can determine the target element from the event object instead:


function EventHandler(e) {
	e = e || window.event;
	var target = e.target || e.srcElement;
	console.log(target);
}

Phew. And you wondered why jQuery became so popular!

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Abhay

    Javascript event handling is very interesting topic. There are differences for passing ‘this’ or implementation in different browsers.
    Thank you for summarizing this.

  • AdamT

    The two preceding comments have no point. Are they spam attempts?

    • http://www.onsman.com Ricky Onsman

      Hey AdamT. Maybe not spam as such, but not quite right either. I removed them, and emphasise that there’s no reflection on Abhay’s comment. Of course, this kinda leaves your comment hanging there, but hey – we know what you mean. Meant. You know.

  • http://www.brothercake.com/ James Edwards

    When you say “all browsers set ‘this’ to the element which fired the event” — that’s not strictly true.

    It would be more accurate to say, they do this *now*. But they never used to. If you go back to circa Firefox 1, Safari 2, and Opera 8, the ‘this’ in that context refers to window (as it should!). It’s only because they bowed to opinion that said it would be more useful to refer to the capturing element (which it is, of course, but it’s still wrong!)

    Really, to find a target element within an event listener, you should use event properties like target or currentTarget

  • Rudie

    Actually, `this` and `e.target` aren’t always the same object and it’s pretty shameful that you don’t know that.

    `e.target` is what you clicked on.

    `this` is the element with the event attached

    PS. Why don’t you use markdown in these comments? Please?

  • http://www.brothercake.com/ James Edwards

    Not quite :)

    ‘e.target’ is the target of the event — which is not necessarily the element you clicked on, it’s the element the event was fired from. They’re usually the same, but not always (because of event bubbling)

    ‘this’ is only the element with the event attached in modern implementations of event listeners, and DOM0 event handlers.

  • Camilo

    Thanks! It worked perfect for me, I spent hours trying to accomplish using ‘this’ without results

    Great job

    regards from Uruguay!