Nested functions & the "this" keyword in JavaScript - 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.

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

what's correct: var declaration if undefined

I have heard different opinions about the usage of var at a situation like this:
function(maybeUndefined) {
if(typeof maybeUndefined === 'undefined')
var maybeUndefined = 'bob';
}
Is it necessary to notate var, or not, because maybeUndefined is an argument of function?
You do not need the var in this case, as mayBeUndefined is already allocated within the scope of the function (hint: listing argument variables in a function definition causes those variables to be declared locally). That var is therefore completely optional, though completely pointless (and a drain on readability).
Example:
function func ( arg1, arg2 ) {
var local1, local2;
function nested1 () {}
function nested2 () {}
// other code
}
Here we have a function declaration. When this declaration is parsed into a function object, a lexical environment (= scope) is created for that function with the following bindings:
arg1
arg2
local1
local2
nested1
nested2
this
arguments
(Notice how there also are two special, built-in bindings: this and arguments. These are always created for all function objects.)
These names are defined as local bindings. (This process is specified in "Declaration binding instantiation". Warning: this algorithm is not meant to be read by humans :-)) Therefore, when a name is defined as a parameter, it is not necessary to declare it as a local variable. This mechanism is independent of whether a value (argument) is passed for that parameter when the function is invoked.
So, even if you invoke the function like so:
func(123);
the name arg2 will still be defined (as a binding in the function's environment), although its value will initially be undefined for that particular invocation.
Btw, if you use the strict language (recommended!), function environments are static which means that the above bindings are garanteed to be the only bindings in the function's environment. The default language, on the other hand, provides certain mechanisms to, dynamically, add/remove bindings from the function's environment. Example:
(function () {
// the name "temp" does not exist as a binding in the function's environment
eval('var temp');
// now it does
delete temp;
// and it's gone again
}());
You should not use var again, it is bad for readability, and the variable will already be scoped locally as a result of being an argument.
Also, you should note that it is not a part of this. this will only be scoped to the function object if the new keyword has been used, and as you do not have a named function, that seems unlikely in this case. Without new, this refers to window (or is undefined if use strict; is used), of which your variable is definitely not a part of as a result of the argument having a local scope.
Interfacing
Including a function argument is effectively the same as scoping a variable (in other words, it's effectively the same thing as defining a function-level reference using the var keyword). The main reason for providing function arguments (in JavaScript) is for your own interfacing preference.
The arguments object
Arguments may still be passed to functions without parameters, and will still be accessible in the 'hidden' arguments object -- which is sort of a "pseudo-array" (if you will), in that it is functionally an array, but is not equipped with the same APIs JavaScript equips the Array (pseudo-type) with:
// The following functions do the same thing, but one is "more readable"
function foo() {
return arguments;
}
function bar(baz, qux) {
return arguments;
}
Evaluation (interface) vs Execution (implement)
When both functions are evaluated (on file 'load'), the arguments object is undefined in every function definition; the object doesn't become "defined" until the function body executes the code therein; to visualize that using pseudo-code, it'd look something like this:
// Function bodies (as objects)
foo : {
arguments : new Array // [undefined]
__proto__ : Empty() // the super-object that allows this object to inherit "functionality"
}
bar : {
arguments : new Array(baz, qux) // [undefined, undefined]
__proto__ : Empty()
}
Function invocation
So when you invoke a function, it "implements" or "executes" its body (its "object"). When it does that, if the objects that have been pushed into the arguments object are defined, then the function can reference them. If not, a reference error will be thrown, logging that the variables are undefined in that scope.
In short:
It isn't necessary to interface function-scope-level variables (aka "private members") using var because the language already attaches the arguments object to all function body objects.
More reading:
JavaScript Memoization: "Function-caching" multiple arguments for better performance:
http://decodize.com/javascript/javascript-memoization-caching-results-for-better-performance/

Function context ("this") in nested functions

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.

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.

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.

Categories