onClick Function "this" Returns Window Object

67,508

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;
}

Solution 3

As other answers already mention, the value of this will depend on how the function that contains it is called. But since your example is about event handlers, I'd like to highlight what cjc343 said on the comments:

You may find it to be more sensible if you remove the inline event handlers.

That's pretty simple, actually. Considering this HTML:

<ul id="list">
    <li id="item1">item 1</li>
    <li id="item2">item 2</li>
    <li id="item3">item 3</li>
</ul>

The following JavaScript will account for both removing inline handlers, and using delegation:

var list = document.getElementById('list');
list.addEventListener('click', function(evt){
    console.log("this is the element the event is bound to: " + this.id);
    console.log("the event target is the clicked element: " + evt.target.id);
});

http://jsfiddle.net/J3Gje/

That will work on all browsers compliant to the W3C event model, including IE9. For older IE, you have to use attachEvent instead of addEventListener, and prepend the event names with "on". More details here.

Share:
67,508
Pori
Author by

Pori

I am a full-stack software engineer, experienced in developing mobile and web applications. My experience has placed me in all stages of development.

Updated on July 09, 2022

Comments

  • Pori
    Pori almost 2 years

    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?

  • RobG
    RobG over 11 years
    this has nothing to do with scope.
  • RobG
    RobG over 11 years
    this is set entirely by how a function is called (ignoring ES5 bind). The calling context (i.e. global or function context, which establishes scope) is irrelevant. If this is not set by the call, it will default to the global object in non-strict mode regardless of where a function was called, and this can be set to any object when called from any context (i.e. it has nothing to do with scope).
  • p_strand
    p_strand over 11 years
    @RobG Ah, I see... thanks for the clarification and correction! I have edited my answer.
  • Dennis
    Dennis over 11 years
    Element.tagName is provided by DOM level 2, just like Node.nodeName. Your recommendations to avoid this and new are troubling - if you learn to use them, they are not confusing.
  • austincheney
    austincheney over 11 years
    @Dennis I disagree. I have never seen any use of this that is more clear or simple than similar logic not using that keyword. Consequently, I have seen numerous examples of people coming from other languages attempting to create class structures with this in order to bend JavaScript to their prior experience, which is not rational. this is also the pronoun of JavaScript, and pronouns do not serve the interests of programming. I am more than happy to accept down votes as I will continue to stand by my opinion.
  • Logic1
    Logic1 over 7 years
    To add portability you could also use like so: <li onClick="foo.call(this)"></li> Called function will inherit the calling element as "this".