javascript scope, why does $(this) equal [window]?

我是研究僧i 提交于 2019-12-11 02:31:31

问题


I have an ajax function (not sure if relevant) that updates html and creates a few links:

<a href="#" class="clickme" onclick="column_click()" title="my title">click me</a>

I'm not sure why, but onclick, if I alert $(this).attr('title') it shows as undefined, and if I alert $(this) it shows [window]

     function column_click(){
            value = $(this);
            console.log(value);

            thetitle= $(this).attr('title');
            console.log(thetitle);
        }

Does anyone know why this is the case?


回答1:


You're confusing the obtrusive and unobtrusive styles of JS/jQuery event handling. In the unobtrusive style, you set up click handlers in the JavaScript itself, rather than in an onclick attribute:

$('.clickme').on('click', column_click);

The above will automatically bind this to the clicked element while the event is being handled.

However, this is not standard JavaScript! It's a feature of jQuery. The on method is smart enough to bind the function to the HTML element when it handles the event. onclick="column_click" doesn't do this, because it isn't jQuery. It uses standard JS behavior, which is to bind this to the global object window by default.

By the way, the reason you see [window] is that $(this) has wrapped window in a jQuery object, so it looks like an array with the window object inside it.

There are three main ways to deal with your problem:

  1. Use unobtrusive binding: $('.clickme').on('click', column_click); in a script at the end of the page, or somewhere in the $(document).ready handler
  2. Bind this manually: onclick="column_click.call(this)"
  3. Avoid using this at all:

    function column_click(e) {
        var value = $(e.target);
        //...
    

Of these, I'd strongly recommend either 1 or 3 for the sake of good coding.




回答2:


This should fix the issue.

onclick="column_click.call(this);"

The reason is that your "click handler" is really just a function. The default is to have this refer to the window object.

In my example above, we are saying "execute column_click and make sure this refers to the a element.




回答3:


You need to pass the parameter in the function of column_click,

<a href="#" class="clickme" onclick="column_click(this)" title="my title">click me</a>



function column_click(obj){
        value = $(obj);
        console.log(value);
    }

Note: this refer window object. so won't work what you expect.




回答4:


A Short Overview of this*

When you execute a function in JavaScript, the default this is window.

function foo() {
    console.log(this);
}

foo(); // => window

The this value can be changed in a number of ways. One way is to call the function as a method of an object:

var x = {
    foo: function() {
        console.log(this);
    }
};
x.foo(); // => This time it's the x object.

Another way is to use call or apply to tell the function to execute in the context of a certain object.

function foo() {
    console.log(this);
}
foo.call(x); // => x object again
foo.apply(x); // => x object as well

If you call or apply on null or undefined, the default behavior will occur again: the function will be executed in the context of window:

function foo() {
    console.log(this);
}
foo.call(null); // => window
foo.apply(undefined); // => window

However, note that in ECMAScript 5 strict mode, this does not default to window:

(function() {

    'use strict';

    function foo() {
        console.log(this);
    }

    foo(); // => undefined
    foo.call(null); // => null
    foo.apply(undefined); // => undefined

})();

You can also set the this by using bind to bind the function to an object before it is called:

function foo() {
    console.log(this);
}

var bar = {
    baz: 'some property'
};

var foobar = foo.bind(bar);

foobar(); // => calls foo with bar as this

Conclusion

You're using this code:

<a href="#" class="clickme" onclick="column_click()" title="my title">click me</a>

Which means that when the link is clicked, it executes column_click();. That means the column_click function gets executed as a plain function, not a method, because (1) it's not called as a property of an object (someobject.column_click();), (2) it's not called with call or apply, and (3) it's not called with bind. Since it's not running in strict mode, the default this is window.

How to Fix Your Problem

Therefore, to fix your problem, you can simply use call (or apply) to tell the function to execute in the context of the element. Within the small code inside the attribute value, this refers to the element. So we can use column_click.call(this). It's that easy!

<a href="#" class="clickme" onclick="column_click.call(this);" title="my title">click me</a>

However, it would probably make more sense just to pass the element as an argument:

<a href="#" class="clickme" onclick="column_click(this);" title="my title">click me</a>

and change your function to accept the argument:

function column_click(el) {
    // Use el instead of this...
}

* Getting Technical

this in JavaScript is dynamically scoped. This behavior differs from all other variables which are lexically scoped. Other variables don't have a different binding depending on how the function is called; their scope comes from where they appear in the script. this however behaves differently, and can have a different binding depending not on where it appears in the script but on how it's called. This can be a source of confusion for people learning the language, but mastering it is necessary in order to become a proficient JavaScript developer.




回答5:


You're using jQuery right? Why not:

$(".clickme").click(function() {
  value = $(this);
  console.log(value);

  thetitle= $(this).attr('title');
  console.log(thetitle);
});

// or

$(".clickme").click(column_click);


来源:https://stackoverflow.com/questions/13373365/javascript-scope-why-does-this-equal-window

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!