问题
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:
- Use unobtrusive binding:
$('.clickme').on('click', column_click);in a script at the end of the page, or somewhere in the$(document).readyhandler - Bind
thismanually:onclick="column_click.call(this)" Avoid using
thisat 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