onClick Function "this" Returns Window Object

I've come across a head scratching issue with my JavaScript application.

If I write an element like this:

<li onClick="alert(this.tagName)"></li>

I get "LI."

However if I do this:

<li onClick="foo()"></li>

Where "foo()" is:

function foo(){ alert(this.tagName); }

I get "undefined."

I am away how "this" is supposed to work in regards to attached functions. But, I am baffled because "this" is not picking up the element, but apparently defaulting to "window." I can't figure out why this is happening.

Does anyone have an explanation?


Solution 1:

That's because you aren't passing a reference to this in the JavaScript function call. this in the JavaScript function doesn't refer to the same object as in the onClick example. Try this instead:

 <li onClick="foo(this)"></li>

 function foo(item){ alert(item.tagName); }

Solution 2:

In an inline listener:

> <li onClick="alert(this.tagName)"></li>

The onclick attribute value is effectively wrapped in a function and called with the element set to this, e.g.

function anon() {
  /* attribute value */
}

anon.call(element);

When you put a function in the body, you are essentially getting:

function anon() {
  foo();
}

Here, this within anon will be the element, but since foo is called without setting this, it will be undefined. In non-strict mode, this will default to the global object (window in a browser). In strict mode, this inside foo will be undefined.

One solution is to pass an element reference to the function:

<li onclick="foo(this)" ... >

then in the function:

function foo(callingElement) {
  ...
}

or even:

<li onclick="foo.call(this)" ... >

function foo() {
  var callingElement = this;
}