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.
Related
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 ;)
Is this:
(function(a) {
return 3;
})(this);
equivalent to:
(function() {
return 3;
})();
If there are any differences, please explain
Here's the difference I think you're looking for: the second example has access to the outer this (through the a variable), while the second example does not.
Normally, you don't need to pass in arguments to an IIFE (although you certainly can, to get more readable or modular code), because newly-declared functions have access to their outer scope variables:
var foobar = 5;
(function() {
// I can use the outer-scope `foobar` in here!
})();
However, this is an exceptional case, because the newly-created function will have its own this that will shadow the outer this:
// outer here, `this` is one thing
(function() {
// in here, `this` might be something else
// because each new functions invocation sets `this` within the function
})();
You can see shadowing behavior with non-this variables like this:
var foobar = 5;
(function() {
var foobar = 7;
// I can't use the outer-scope `foobar`
// because it is shadowed by local-scope `foobar`
})();
A similar thing happens with this. In my foobar example, the shadowing was done explicitly, but with this, the shadowing always happens, because each function gets a new local-scope this.
You can access the outer this by aliasing it a new name, done here by formal argument:
// outer here, `this` is one thing
(function(outerThis) {
// in here, `this` might be something else
// but `outerThis` refers to the outer `this`
})(this);
If you don't alias the outer this to a new name, you will not have access to it, because it will be shadowed by local this. Note that you can also alias your outer this to another outer-scope variable, like:
var outerThis = this;
(function() {
// we can access the outer-scope `outerThis` because it is not shadowed
})();
Well, the first you're passing an argument to, but it is never used. However, the functionality is the same for both. The second is slightly faster, due to not passing an argument for no reason, assuming this isn't just optimized away.
It depends on how you define equivalent.
If you define it in terms of what the functions actually do, then, yes, they are equivalent. Although, of course, this is only true for their current content. One difference is that the first one has access to the outer this, while the second one doesn't - although this does not matter in your example.
Regarding to your comment whether just passing this makes a difference here: No, it does not.
If you define equivalent in a different way, then the functions may be different, e.g. when defining equivalent as having the same arity.
I guess the obvious counter-question would be what's the use case behind your question: Why do you ask this? (If it's not just out of curiosity and for academical reasons.)
I'm playing around with scopes in JavaScript and I was curious about something I ran across when calling a function from an array. In the below example I work with three different scopes. One bound to an Object called foobar, one bound to window and then a third one which actually refers to the function itself. I'm just curious why the function is scoped to itself and not to the global window object. Is it because Array access is a function call itself so the stored function is in a local scope?
var foobar = {
doWork: function() {
console.log('doing some work...');
console.log(this);
}
}
foobar.doWork(); // `this` will refer to foobar
var doWorkClone = foobar.doWork;
doWorkClone(); // `this` will refer to window
var workClones = [];
workClones.push(foobar.doWork);
workClones[0](); // `this` will refer to the doWork function itself
They behave the same way. In a.b(), the function a.b is called with this set to a.
foobar.doWork(); // function is `foobar.doWork`, `this` is `foobar`
workClones[0](); // function is `workClones[0]`, `this` is `workClones`
This is because the . and [] notation are functionally the same thing. It does not matter which one you use, nor does it matter whether you're dealing with an array or not.
to understand this, litteraly, it might be helpfull to see how the js works under the hood.
when you write f(args), js will execute f.call(this, args). Hence this always refers to where you call the function from.
In your case:
foobar.doWork() --> foobar
doWorkClone() --> window or wrapping expression
workClones[0]() --> "0" is in workClones, so workClones
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
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(){
});