Function context ("this") in nested functions - javascript

When you invoke a top-level function in Javascript, the this keyword inside the function refers to the default object (window if in a browser). My understanding is that it's a special case of invoking the function as method, because by default it is invoked on window (as explained in John Resig's book, Secrets of the JavaScript Ninja, page 49). And indeed both invocations in the following code are identical.
function func() {
return this;
}
// invoke as a top-level function
console.log(func() === window); // true
// invoke as a method of window
console.log(window.func() === window); // true
So far so good... Now here is the part I don't understand:
When a function is nested in another function and invoked without specifying an object to invoke on, the this keyword inside the function also refers to window. But the inner function cannot be invoked on window (see code below).
function outerFunc() {
function innerFunc() {
return this;
}
// invoke without window.* - OK
console.log(innerFunc() === window); // true
// invoke on window
//window.innerFunc(); - error (window has no such method)
console.log(window.innerFunc) // undefined
}
outerFunc();
It makes perfect sense that the nested function isn't available on window, as it is after all nested... But then I don't understand why the this keyword refers to window, as if the function was invoked on window. What am I missing here?
EDIT
Here is a summary of the great answers below and some of my follow up research.
It is incorrect to say that invoking a function "normally" is the same as invoking it as a method of window. This is only correct if the function is defined globally.
The function context (the value of the this keyword) does not depend on where / how the function is defined, but on how it is being invoked.
Assuming that the code is not running in in strict mode, Invoking a function "normally" will have the function context set to to window (when running in a browser, or the corresponding global object in other environments).
An exception to the above rules is the use of bind to create a function. In this case even if the function is invoked "normally", it could have a context other than window. That is, in this case the context is determined by how you create the function, rather than how you invoke it. Although strictly speaking this isn't accurate, because bind creates a new function that internally invokes the given function using apply. The context of that new function will still be determined by the way it's invoked, but it shields the context of the function it internally invokes by using apply.
By invoking "normally" I refer to the following simple way of invocation:
myFunction();
To complete the picture, here is a brief coverage of other ways of invocation and the corresponding context:
As a property of an object (method) - the context is the object
Using apply or call - the context is specified explicitly
With the new operator (as a constructor) - the context is a newly created object
Feel free to update the above as necessary, for the benefit of people with similar questions. Thanks!

You can call any function that is in scope with functionName(). Since you haven't called it on an object, it will be called in the context of the default object (window). (IIRC, it will be called in the context of undefined if you are in strict mode).
The default object for context has nothing to do with where a function is defined or what scope that function appears in. It is simply the default object.
If a function is a property of an object, you can call it as reference.to.object.function(), and it will be called in the context of object instead of the default object.
Other things that change the context are the new keyword and the apply, call, and bind methods.

In JavaScript, when a function is invoked without an explicit context, the context is the global object. In the case of web browsers, the global object is window.
Additionally, JavaScript has functional scope, so any variables or functions within a function are not accessible in a scope outside of that function. This is why you can't access window.innerFunc.

Whether a function is nested inside another one has nothing to do with the value of this when the function is called. The only things that matter are:
If the function is "found" by traversing a property on an object, then the value of this will be a reference to that object:
someObject.prop( whatever );
It doesn't matter how the function was declared.
If you use call() or apply() to invoke a function, then the value of this is taken from the first argument to whichever of those functions you use.
If you've created a bound wrapper for the function with bind(), then the value of this will be as requested when bind() was called.
If you're calling a function as a constructor with new, then this will refer to the newly-created object instance.
Otherwise, this is either a reference to the global context, or else it's undefined (in "strict" mode or in an ES5-compliant runtime).
The "location" in the code where a function is defined does matter, of course, in that the scope includes whatever symbols it includes, and those are available to the function regardless of how a reference to it is obtained.

It does not depend where the function is declared but how it is called:
var obj = {
f: function() {
return this;
}
}
var f = obj.f;
console.log(obj.f()) // obj
console.log(f()) // window/default obj
Or in other words. The syntax obj.f() executes the function with this=obj while f() executes the function with this=window. In JavaScript the caller specifies the value of this.

When you define func in the global scope, it actually is assigned as a property of the window object. That is, the window object holds all globally scoped variables. (*) Therefore, func and window.func represent the same thing. innerFunc is defined inside a function scope and is not available outside of that scope. Therefore, window.innerFunc is (still) undefined.
However, the this context is determined by how you call the function. When you call a method like obj.method(), the this context is set to obj. On the other hand, you can also call the method on its own:
var f = obj.func;
f(); // in this call: this === window
In this case, you're not calling a function on an object and thus the this context is set to the default. The default however is the global scope and as stated above, this is represented by window.
You can always override the this context by using Function.prototype.call() or Function.prototype.apply() which take a this context as first argument. For example:
var f = obj.func;
f.call(obj); // in this call: this == obj
(*) Note that this only applies to JavaScript running inside a browser. In other environments, this may differ. For example, in Node.js the GLOBAL variable holds the global scope.

Related

How does javascript's 'this' binding work when assigning a "method" to another variable?

Consider:
function Thing() {
this.prop = null
}
Thing.prototype.whoIsThis = function() {
console.log(this)
}
a = new Thing()
a.whoIsThis() // logs '> Thing {...}'
f = a.whoIsThis
f() // logs '> Window {...}'
So this is not bound to the Thing in the second call. How does this work in this situation? Isn't a.whoIsThis a "method" of a Thing regardless of any variable its assigned to?
When you say a.whoIsThis, it will refer the function object only. The function object will have no reference to the object on which it is attached. But when you invoke the function, JavaScript dynamically decides the current object and sets that as this inside the function.
This dynamicity allows us to use any object as the current object in the runtime.
But when you simply invoke a function object, without any object reference, by default, JavaScript will set this as the global object (window object in browser) and in Strict mode, this will be set to undefined.
A function's this keyword behaves a little differently in JavaScript compared to other languages. In most cases, the value of 'this' is determined by how a function is called, when 'this' is inside a function.
1) When a function is called as a method of an object, its this is set to the object the method is called on.
2) When a function is called directly, the value of this is not set by the call. Since the code is not in strict mode, the value of this must always be an object so it defaults to the global object. In strict mode, the value of this remains at whatever it's set to when entering the execution context, so 'undefined'.
More info: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
This binding is decided at run time and not at author time
having f = a.whoIsThis is just another reference to the function WhoIsThis
now Imagine If you have the function declared in the global scope..which is really what f is now..and when calling f JS at run time run the function as if it was declared in the global scope(as I mentioned) so It asks ..what this refers to if I'm in the global scope => default binding rule would answer..it's simply the global(window) object

'this' in a function VS 'this' in a method

From Javascript-Garden:
Foo.method = function() {
function test() {
//this is set to the global object
}
test();
}
In order to gain access to Foo from within test, it is necessary to create a local variable inside of method that refers to Foo:
Foo.method = function() {
var that = this;
function test(){
//Use that instead of this here
}
test();
}
Could anyone explain this? As far as I understood, this refers to the global object if it's called in the global scope. But here it's called inside of a function, which is inside a method (first example). Why exactly does it refer to the global object, while the second example doesn't?
As far as I understood, this refers to the global object if it's called in the global scope.
No. this will refer to the default object if the function is called without explicit context. The scope is irrelevant. (In strict mode it will refer to undefined instead).
Why exactly does it refer to the global object
We can't tell what it refers to. The value of this is determined by how the function is called, not how it is defined.
Now you have updated the example, we can see that it is called without context, so this (in the inner function) will be the default object, which in a web browser is window (it would be undefined in strict mode).
while the second example doesn't?
In the second example, the inner function doesn't use this (which will have the same value as the previous example).
The second example uses that instead. that is defined in the scope of the outer function and is set to whatever the value of this is when that function is called.
Assuming that function is called as Foo.method() then (outer) this (and hence that) will be Foo because that is the context on which method was called.
this in a function isn't set when you define the function. It's only dynamically defined to the receiver of the function call.
If you call foo.test(), this in test will be foo.
But if you do
var f = foo.test;
f();
then this in f (which is foo.test) will be the external object (window if you're executing it at the root level).
It would be the same with
foo.test.call(window);
The second example uses a closure to place the outer functions variables on the scope chain of the inner function.
Foo.method = function() {
var that = this;
function test(){
//This function has access to the outer variables scope chain.
}
}

Nested functions & the "this" keyword in JavaScript

"The this keyword always refers to the object that the containing function is a method of."
Great, sounds simple enough, but here's what I'm wondering about...
For example:
function func1() {
function func2() {
alert(this == window); // true
}
func2();
alert(this == window); // true
}
func1.func3 = function () {
alert(this == window); // false
alert(this == func1); // true
};
func1();
func1.func3();
Now, since func1 is actually a method of the global (window) object (a function object assigned to the property func1 of the global object) it makes sense that this inside func1 refers to the global object, and since func3 is a method of func1's function object it makes sense that this inside func3 refers to func1's function object.
The thing that bothers me is func2. I know that this inside a nested function is also supposed to reference the global object, but I'm not sure why since func2 is NOT a method of the global object. As far as I understand (and this is the part I might be completely wrong about) func2 is a method of func1's call (activation / variable) object. Now, if I'm right about this (and I'm not sure that I am) then shouldn't this inside func2 refer to func1's call object instead of the global object?
So, I guess my question would be: Is a nested function a method of the call (activation) object of the function it is nested in, and if so, shouldn't this refer to that call object instead the global object?
The this keyword always refers to the object that the containing function is a method of.
No. Unfortunately, it is not easy as that. The documentation of the this keyword at MDN gives a good overview. It is set to the object when the function is called as a method on it, but there are other possibilies. The default is that this is undefined when it is called without anything special, like you do with func1 and func2. For sloppy (non-strict) mode functions undefined (and null) are not used though, this does point to the global object (window in browsers) for them in that case - what you are observing.
But it could also point to fresh object instances when the function is called as a constructor (with the new keyword), or to an event target (like a DOM element) when used as a handler. Last, but not least, it could be set manually with call, apply or bind…
this has nothing to do with nesting. Nesting function declarations/expressions only affects the scope ("privacy", availability) of variables. While the variable scope of a function never changes, the value of this can be different on every invocation - it is more like an extra argument.
The meaning of the this keyword inside a function depends on the way the function is invoked. There are 4 different function invocation patterns in JavaScript.
function invocation pattern foo()
method invocation pattern o.foo()
constructor invocation pattern new foo
call/apply pattern foo.apply(...) or foo.call(...)
Only in #2 is it the case that this inside the function refers to the object of which the function is a method.
You are invoking func2() with the function invocation pattern. When doing so, this refers to the global object.
As suggested by #Bergi, see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/this for more detail on the meaning of this and the different function invocation patterns.
but I'm not sure why since func2 is NOT a method of the global object.
Any thing defined inside a function is local to the scope of that function. So func2 belongs to the local scope of func1 and therefore is not attached to window.
In Javascript, the value of this is generally based on how you call the function. When you call a function without any leading object, this is usually set to the global parent object, which is window.
You can explicitly set the value of this in three ways:
myObj.func(a, b); //this set to myObj implicitly because myObj is the parent
func.call(myObj, a, b); //this set to myObj explicitly; the first argument
//to call sets the value of this for that function
func.apply(myObj, [a, b]); //this set to myObj explicitly; the first argument
//to apply also sets the value of this for that
//function.
this can be a tricky concept. MDN has a good article about this.

What is and how to determine the calling context of an invoked method or function within another function?

What is the calling context of an invoked method or function within another function?
In browsers, the default calling context is the window object. In various situations, how do I avoid this?
If a function is invoked -- for example, by theFunction(); -- within a containing function, is the invoked function's calling context the containing function?
In these two examples
(function ()
{
something.initialize();
}());
and
(function ()
{
something.initialize.call(this);
}());
..., is the calling context the same?
They are not the same. In the following I assume you were talking about this when you mentioned context.
In the first example, inside initialize, this will refer to something. In the second one, it will refer to the global object, which is window in browsers.
What this refers to is determined by how the function was called. There are five cases:
func(), calling a function "standalone": this refers to the global object.
new func(), calling a function as constructor method: this will refer to an empty object which inherits from func.prototype.
obj.func(), calling a function as property of an object: this will refer to the object obj.
func.apply(foo), func.call(foo), invoking a function with apply or call: this refers to the object passed as first argument.
ECMAScript 5 also introduced .bind() [MDN] which enables you to bind this to a certain object, without immediately calling the function.
Now you understand why in your second example, inside initialize, this will refer to window:
The outer function is called "standalone" (first case), so this inside of it will refer to window. Next you are passing this to call, which sets this inside initialize to window (fourth case).
Further reading:
MDN - this, explains all I write above with some examples.
No, they are not the same. The first parameter to the call method sets the value of this inside that function; example 1's this should theoretically contain a reference to something; example 2's this corresponds to the this of your self executing function.
The environment available to a function when it is invoked is based on several things.
the this binding which is different for the initialize method in your example
the actual parameter bindings which are not and a binding for a special arguments object
a binding for the function name, if any
the environment chain at the time the function was created. This is the "close" part of the term "closure". A javascript function "closes over" all the variables that are in-scope when the function object comes into existence.
In your example, only 1 is affected by the choice to use call which has the effect of passing this instead of something as the this value in the method body.
The relevant part of the spec starts at section 10.4.3
The following steps are performed when control enters the execution context for function code contained in function object F, a caller provided thisArg, and a caller provided argumentsList: ...
Functions don't create context, unless it's a constructor (a function called with new).
In your second example the context is undefined (which gets transformed into the global object , window). In ES5 strict mode it won't be transformed into anything.
I recommend John Resig's interactive JavaScript tutorial on the topic of context.

Changing the context of a function in JavaScript

This is taken from John Resig`s Learning Advanced Javascript #25, called changing the context of a function.
1) in the line fn() == this what does this refer to? is it referring to the this inside the function where it says return this?
2) although I understand the purpose of the last line (to attach the function to a specific object), I don't understand how the code does that. Is the word "call" a pre-defined JavaScript function? In plain language, please explain "fn.call(object)," and explicitly tell me whether the object in parens (object) is the same object as the var object.
3). After the function has been assigned to the object, would you call that function by writing object.fn(); ?
var object = {};
function fn(){
return this;
}
assert( fn() == this, "The context is the global object." );
assert( fn.call(object) == object, "The context is changed to a specific object."
call is a function defined for a Function object. The first parameter to call is the object that this refers to inside the function being called.
When fn() is called without any particular context, this refers to the global context, or the window object in browser environments. Same rules apply for the value of this in the global scope. So in fn() == this), this refers to the global object as well. However, when it is called in the context of some other object, as in fn.call(object), then this inside fn refers to object.
fn.call(object) does not modify or assign anything to object at all. The only thing affected is the this value inside fn only for the duration of that call. So even after this call, you would continue calling fn() as regular, and not as object.fn().
The example simply demonstrates that the this value inside a function is dynamic.

Categories