jquery mystery 'this' element [duplicate] - javascript

The behavior of "this" when function bar is called is baffling me. See the code below. Is there any way to arrange for "this" to be a plain old js object instance when bar is called from a click handler, instead of being the html element?
// a class with a method
function foo() {
this.bar(); // when called here, "this" is the foo instance
var barf = this.bar;
barf(); // when called here, "this" is the global object
// when called from a click, "this" is the html element
$("#thing").after($("<div>click me</div>").click(barf));
}
foo.prototype.bar = function() {
alert(this);
}

Welcome to the world of javascript! :D
You have wandered into the realm of javascript scope and closure.
For the short answer:
this.bar()
is executed under the scope of foo, (as this refers to foo)
var barf = this.bar;
barf();
is executed under the global scope.
this.bar basically means:
execute the function pointed by this.bar, under the scope of this (foo).
When you copied this.bar to barf, and run barf. Javascript understood as, run the function pointed by barf, and since there is no this, it just runs in global scope.
To correct this, you can change
barf();
to something like this:
barf.apply(this);
This tells Javascript to bind the scope of this to barf before executing it.
For jquery events, you will need to use an anonymous function, or extend the bind function in prototype to support scoping.
For more info:
Good explanation on scoping
Extending jQuery bind to supportscoping

There's a good explanation on this keyword in JavaScript available at QuirksMode.

You might find this:
Controlling the value of 'this' in a jQuery event
or this:
http://www.learningjquery.com/2007/08/what-is-this
Useful.

Get the book: JavaScript: the Good Parts.
Also, read as much as you can by Douglas Crockford
http://www.crockford.com/javascript/

You may use Function.apply on the function to set what this should refer to:
$("#thing").after($("<div>click me</div>").click(function() {
barf.apply(document); // now this refers to the document
});

This is because this is always the instance that the function is attached to. In the case of an EventHandler it is the class that triggered the event.
You can help your self with an anonymous function like this:
function foo() {
var obj = this;
$("#thing").after($("<div>click me</div>").click(function(){obj.bar();}));
}
foo.prototype.bar = function() {
alert(this);
}

this.bar(); // when called here, "this" is the foo instance
this comment is wrong when foo is used as a normal function, not as a constructor.
here:
foo();//this stands for window

Related

JavaScript: invocation as a function/method

I am trying to sharpen my JavaScript skills and I am aware that there are four basic ways to invoke a function - which alter the way this is defined. The two I am interested in are the basic two:
Invocation as a function
Invocation as a method
Which is fine. The first, this will refer to the window object:
function doSomething() {
console.log(this);
}
doSomething(); // window is logged
And the second this will refer to the object it is being executed from within:
var t = {
doSomething: function () {
console.log(this);
}
};
t.doSomething(); // t is logged
Which is all fine. However, is it correct to say, that in these two invoking methods, this is always going to return the object the method is contained within (if that makes sense)?
In the first example, doSomething() is, in reality, defined within the window object - so is a property of the window object, even if we do not define it (or reference it).
Therefore, can it not be said that, in reality, invocation as a function is invocation as a method? Or not?
Imagine defining your function, not in the scope of the global object like you did, but in the scope of another function:
function outer() {
var inner = function(){console.log(this)};
inner();
};
outer();
What do you think the this will be bound to ? What will be printed ?
You might believe it will be the outer function object but its turns out that it will always be the global object.
It is just as if you had written:
function outer() {
var inner = function(){console.log(this)};
inner.call(window);
};
outer();
This is a quite hazardous and far from intuitive JS "feature".
So, to get back to your first example, what you are doing is basically this:
doSomething = function () {
console.log(this);
}
doSomething().call(window);
And, like Yoshi pointed out, if you were using the ES5's strict mode, you would end up doing something like that instead, which is, in my opinion, far less dangerous:
doSomething().call(undefined);
It also gives you a strong hint about the fact that you should never use this in a function ;)

javascript "this" points to Window object again

I asked a question on Javascript this points to Window object regarding "this" points to Window object.
here is source code
var archive = function(){}
archive.prototype.action = {
test: function(callback){
callback();
},
test2: function(){
console.log(this);
}
}
var oArchive = new archive();
oArchive.action.test(oArchive.action.test2);
Tim Down wrote "but that function is then called using callback(), which means it is not called as a method and hence this is the global object".
What are differences between calling a function by its actual name and callback() as shown on the source code?
How does console.log(this) in test2 points to Window when it is inside archive.action???
In JavaScript you can invoke functions using 4 different invocation patterns:
Function invocation
Method invocation
Apply/Call invocation
Construction invocation
The patterns mainly differ in how the this parameter is initialized.
When you use oArchive.action.test2(), you would be invoking the test2() function with the method pattern, and in this case this would be bound to the action object. JavaScript will use the method pattern whenever the invocation expression contains a refinement (i.e. the . dot expression or the [subscript] expression).
On the other hand, when a function is not the property of an object, then it is invoked using the function pattern. In this case, the this parameter is bound to the global object, and in fact this is how JavaScript is invoking your callback() function.
Douglas Crockford in his Good Parts book, describes this as a mistake in the design of the language, and suggests some possible workarounds. In you case, one easy workaround would be to invoke the callback using call() or apply(), as Tim Down suggested in your previous question:
callback.call(this);
This works because the Apply/Call invocation pattern lets you choose the value of this, which is what you require.
In javascript the this keyword is set to the owner of a function. Function objects do not maintain their ownership themselves, instead the ownership is deduced from the way we call a function.
eg:
var foo = function() {
alert('hello');
};
var abc = {};
abc.bar = foo;
Simply calling the function like
foo();
gives the interpreter no clue about what object the function might be attached to. It may be attached to multiple objects, it may be a variable etc. So the interpreter sets this to the global object.
But however, when calling a function like
abc.bar();
the interpreter knows that function is attached to abc object, therefore this is set to abc. Even if both bar and foo refer to the same function object, the difference in the calling pattern causes this to behave differently.

"this" keyword in event methods when using JavaScript prototype object

I'm trying to access the member variables of a prototype class in JavaScript in an event handler -- something I'd typically use the "this" keyword for (or "that" [copy of this] in the case of event handlers). Needless to say, I'm running into some trouble.
Take, for example, this HTML snippet:
<a id="myLink" href="#">My Link</a>
And this JavaScript code:
function MyClass()
{
this.field = "value"
this.link = document.getElementById("myLink");
this.link.onclick = this.EventMethod;
}
MyClass.prototype.NormalMethod = function()
{
alert(this.field);
}
MyClass.prototype.EventMethod = function(e)
{
alert(this.field);
}
Instantiating a MyClass object and calling NormalMethod works exactly like I expect it to (alert saying "value"), but clicking the link results in an undefined value because the "this" keyword now references the event target (the anchor () HTML element).
I'm new to the prototype JavaScript style, but in the past, with closures, I've simply made a copy of "this" in the constructor:
var that = this;
And then I could access members variables in event methods via the "that" object. That doesn't seem to work with prototype code. Is there another way to achieve this?
Thanks.
You need:
this.link.onclick = this.EventMethod.bind(this);
...'bind' is part of Prototype, and returns a function which calls your method with 'this' set correctly.
Your "that=this" closure idiom is still applicable:
function MyClass()
{
...
var that = this;
this.link.onclick = function() {
return that.EventMethod.apply(that, arguments);
// that.EventMethod() works too here, however
// the above ensures that the function closure
// operates exactly as EventMethod itself does.
};
}
You should try
this.link.onclick = this.EventMethod.bind(this);
As stated above, using bind which is a part of the Prototype library is a clean way to solve this problem. This question is a duplicate of another SO question which is answered here with implementation of the bind method without including the whole prototype library :
https://stackoverflow.com/a/2025839/1180286

Just when I think I finally understand Javascript scope

I run in to something that illustrates how I clearly don't get it yet.
Can anyone please explain why the value of "this" changes in the following?
var MyFunc = function(){
alert(this);
var innerFunc = function(){
alert(this);
}
innerFunc();
};
new MyFunc();
In JavaScript, this represents the context object on which the function was called, not the scope in which it was defined (or the scope in which it was called). For MyFunc, this references the new object being created; but for innerFunc, it references the global object, since no context is specified when innerFunc is called.
This tends to trip up those used to Java or similar OO languages, where this almost always references an instance of the class on which the method being called is defined. Just remember: JavaScript doesn't have methods. Or classes. Just objects and functions.
See also: What is the rationale for the behavior of the ‘this’ keyword in JavaScript?
Just do the following:
var MyFunc = function(){
var self = this;
alert(self);
var innerFunc = function(){
alert(self);
}
innerFunc();
};
new MyFunc();
This way self will always mean this, irrespective of where you're calling it from, which is usually what you want.
As a sidenote, "this" isn't necessarily referencing the actual function all the time, since you can invoke a function with a "forced" this-reference, think about an event-handler, in which this will refer to the actual element that fired the event.
using
yourFunction.apply(thisReference, arguments)
you can invoke it where "this" will point to whatever you pass on as first argument.
At first glance I'd say it's because the outer 'this' is in reference to MyFunc and the inner 'this' is in reference to innerFunc.
However, Javascript isn't something I have any particular expertise in.

var self = this?

Using instance methods as callbacks for event handlers changes the scope of this from "My instance" to "Whatever just called the callback". So my code looks like this
function MyObject() {
this.doSomething = function() {
...
}
var self = this
$('#foobar').bind('click', function(){
self.doSomethng()
// this.doSomething() would not work here
})
}
It works, but is that the best way to do it? It looks strange to me.
This question is not specific to jQuery, but specific to JavaScript in general. The core problem is how to "channel" a variable in embedded functions. This is the example:
var abc = 1; // we want to use this variable in embedded functions
function xyz(){
console.log(abc); // it is available here!
function qwe(){
console.log(abc); // it is available here too!
}
...
};
This technique relies on using a closure. But it doesn't work with this because this is a pseudo variable that may change from scope to scope dynamically:
// we want to use "this" variable in embedded functions
function xyz(){
// "this" is different here!
console.log(this); // not what we wanted!
function qwe(){
// "this" is different here too!
console.log(this); // not what we wanted!
}
...
};
What can we do? Assign it to some variable and use it through the alias:
var abc = this; // we want to use this variable in embedded functions
function xyz(){
// "this" is different here! --- but we don't care!
console.log(abc); // now it is the right object!
function qwe(){
// "this" is different here too! --- but we don't care!
console.log(abc); // it is the right object here too!
}
...
};
this is not unique in this respect: arguments is the other pseudo variable that should be treated the same way — by aliasing.
Yeah, this appears to be a common standard. Some coders use self, others use me. It's used as a reference back to the "real" object as opposed to the event.
It's something that took me a little while to really get, it does look odd at first.
I usually do this right at the top of my object (excuse my demo code - it's more conceptual than anything else and isn't a lesson on excellent coding technique):
function MyObject(){
var me = this;
//Events
Click = onClick; //Allows user to override onClick event with their own
//Event Handlers
onClick = function(args){
me.MyProperty = args; //Reference me, referencing this refers to onClick
...
//Do other stuff
}
}
If you are doing ES2015 or doing type script and ES5 then you can use arrow functions in your code and you don't face that error and this refers to your desired scope in your instance.
this.name = 'test'
myObject.doSomething(data => {
console.log(this.name) // this should print out 'test'
});
As an explanation: In ES2015 arrow functions capture this from their defining scope. Normal function definitions don't do that.
var functionX = function() {
var self = this;
var functionY = function(y) {
// If we call "this" in here, we get a reference to functionY,
// but if we call "self" (defined earlier), we get a reference to function X.
}
}
edit: in spite of, nested functions within an object takes on the global window object rather than the surrounding object.
One solution to this is to bind all your callback to your object with javascript's bind method.
You can do this with a named method,
function MyNamedMethod() {
// You can now call methods on "this" here
}
doCallBack(MyNamedMethod.bind(this));
Or with an anonymous callback
doCallBack(function () {
// You can now call methods on "this" here
}.bind(this));
Doing these instead of resorting to var self = this shows you understand how the binding of this behaves in javascript and doesn't rely on a closure reference.
Also, the fat arrow operator in ES6 basically is the same a calling .bind(this) on an anonymous function:
doCallback( () => {
// You can reference "this" here now
});
I haven't used jQuery, but in a library like Prototype you can bind functions to a specific scope. So with that in mind your code would look like this:
$('#foobar').ready('click', this.doSomething.bind(this));
The bind method returns a new function that calls the original method with the scope you have specified.
Just adding to this that in ES6 because of arrow functions you shouldn't need to do this because they capture the this value.
I think it actually depends on what are you going to do inside your doSomething function. If you are going to access MyObject properties using this keyword then you have to use that. But I think that the following code fragment will also work if you are not doing any special things using object(MyObject) properties.
function doSomething(){
.........
}
$("#foobar").ready('click', function(){
});

Categories