In the browser, it is expected that this, inside an IIFE, points to the window object. However, it is undefined in this case.
(function () {
"use strict";
console.log(this) // undefined
// more stuff
}());
In ECMAScript 5's strict mode only, when the value of this is undefined or null (i.e. when not in an object's scope or this is explicitly set), this will not return the global object from the function scope.
What actually happens when a function is called is the following - the ThisBinding is jargon for the value of this when called (ECMA-262).
10.4.3 Entering Function Code
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:
1. If the function code is strict code, set the ThisBinding to thisArg.
2. Else if thisArg is null or undefined, set the ThisBinding to the global object.
If you want the global object, you can use a global variable that is defined in the global scope or use some hacks around this, such as using an immediately invoked new Function()1.
1: Using new Function() works as it does not go into strict mode unless the function has the pragma 'use strict'; within the body of the new Function() itself (reference).
From MDN, under "Securing" JavaScript
First, the value passed as this to a function in strict mode isn't
boxed into an object. For a normal function, this is always an object:
the provided object if called with an object-valued this; the value,
boxed, if called with a Boolean, string, or number this; or the global
object if called with an undefined or null this. (Use call, apply, or
bind to specify a particular this.) Automatic boxing is a performance
cost, but exposing the global object in browsers is a security hazard,
because the global object provides access to functionality "secure"
JavaScript environments must restrict. Thus for a strict mode
function, the specified this is used unchanged:
Example:
"use strict";
function fun() { return this; }
assert(fun() === undefined);
assert(fun.call(2) === 2);
assert(fun.apply(null) === null);
assert(fun.call(undefined) === undefined);
assert(fun.bind(true)() === true);
One way to pass the global object in explicitly in strict mode is to use call(this)
(function(){
"use strict";
console.log(this) // this points to window
// more stuff
}).call(this);
Related
I'm trying to understand what rule for "this" that "use strict"; modifies in the below case.
After reading (http://unschooled.org/2012/03/understanding-javascript-this/) my best guess is that since the functon isStrictModeOn() is not "attached" to anything, this refers to null. Which is suppose to be a more sensible alternative to Javascript just attaching the this to the global object. Is that the correct interpretation of the change that "use strict" is making in this case?
http://www.novogeek.com/post/ECMAScript-5-Strict-mode-support-in-browsers-What-does-this-mean.aspx
function isStrictMode(){
return !this;
}
//returns false, since 'this' refers to global object and '!this' becomes false
function isStrictModeOn(){
"use strict";
return !this;
}
//returns true, since in strict mode, the keyword 'this' does not refer to global object, unlike traditional JS. So here,'this' is null and '!this' becomes true.
That's almost correct. In strict mode, when a function is invoked without a receiver then this is undefined (not null). A better version of that function would be:
function isStrict() {
"use strict";
return (typeof this) === 'undefined';
}
An inherent problem with functions like that is that "strictness" is determined lexically, like scope, so it's static. A tester function that includes its own "use strict"; isn't very useful; it really only tells you whether the JavaScript runtime understands strict mode. One without its own "use strict"; tells you whether the lexical context in which it's defined is in strict mode. That is:
function isStrict() {
function test() {
return (typeof this) === 'undefined';
}
return test();
}
will tell you, when called, whether a "use strict"; was in effect for the scope at which the function is defined. I guess that could be useful. However, if a reference to that function "leaks" into some other context whose "strictness" differs, it's going to continue to report on its static strictness at the point of its definition.
Personally, I would opt for simply ensuring that my code is definitely in strict mode by invoking "use strict"; at the outermost layer possible. That way there's really no need to check for it.
I was under the impression that the "this" keyword represents the current owner that is in scope. Obviously, this is wrong. Let me get to the code:
alert(this); // alerts as [object Window] -- Okay
function p1() {
alert(this);
}
var p2 = function() {
alert(this);
}
p1(); // alerts as undefined -- ???
p2(); // alerts as undefined -- ??
window.p1(); // alerts as [object Window] -- Okay
window.p2(); // alerts as [object Window] -- Okay
The code above first alerts [object Window], as I would expect but then the next two calls to p1() and p2() alert "this" as "undefined". The final two calls to p1() and p2() alert "this" as [object Window].
Isn't it the case that p1() and p2() exist in the global (i.e., window) scope? I thought that calling window.p1() is synonymous with calling p1(), just like calling alert() is synonymous with window.alert().
To my (C#) way of thinking, p1() and p2() are in the global scope. These functions are members of the global window object so when they refer to "this" they should be referring to [object Window]. Obviously, I'm very wrong here.
Becasue you are using strict mode and as per the spec:
If this is evaluated within strict mode code, then the this value is not coerced to an object.
The code you have does alert window in all instances of alert, but because you are in strict mode, it is undefined (as it should be)
UPDATE: chrome dev tools alerts window not undefined, however if you wrap it in a self executing function you get undefined as expected
(function(){
'use strict';
alert(this);
}());
When you call a function like foo(), then the value of this depends on whether the code runs in strict mode or not (the default actually).
In strict mode, this will be undefined (as you already found out).
In "loose mode" this will indeed refer to window, but that's not because the functions are global, i.e. "owned" by the global scope. You get the same behavior for local functions:
(function() {
function foo() {
console.log(this); // logs the window object, but `foo` is not global
}
foo();
}());
This is simply an explicitly defined behavior:
If the function code is strict code, set the ThisBinding to thisArg.
Else if thisArg is null or undefined, set the ThisBinding to the global object.
Else if Type(thisArg) is not Object, set the ThisBinding to ToObject(thisArg).
...
As you can see, in "loose" mode, if thisArg is undefined, which is the case if you call the function "normally" as foo(), then it will be set to window explicitly.
this is what denotes you are referring to that object you are. It is mostly used in Object Oriented Programming to differentiate between an object's self versus input variables.
Example (pseudo code):
var1 //instance variable of object
void Constructor(var1){
this.var1 = var1
}
What this describes is the constructor takes in a var called var1, and sets it's own variable var1 to it.
In your case, I would assume that when in a function:
function p1() {
alert(this);
}
being called as p1();, it is not strictly in an object context, therefore this does not mean anything. By calling it from the window's context window.p1();, you are making the window object call the function, therefore giving this a value.
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
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.
Why does the following work:
function sum(a,b) { return a + b; }
var result = sum.call(null,3,4); // 7
Why is result defined? I am invoking sum as a method of null. But null is not an object and cannot have properties!
What is going on?
The first argument for Function.prototype.call is the context, which defines the this value for the execution context of the invoked function, nothing else.
So basically, you're saying that this is referring to null (at least, in ES5 strict mode), but since you don't access this anyway, it makes no difference.
In non-strict mode, this cannot be null, so it's replaced with the global object instead.
When you use .call or .apply with null or undefined, the default this (usually window) is automatically used instead if not in strict mode.
From MDN (emphasis mine):
thisArg
The value of this provided for the call to fun. Note that this may not be the actual value seen by the method: if the method is a function in non-strict mode code, null and undefined will be replaced with the global object, and primitive values will be boxed.
If you are in strict mode, it actually will be null or undefined.
(function() {
'use strict';
return this;
}).call(null); // null
(function() {
'use strict';
return this;
})(); // undefined
Its not. NULL in this case specifies to what object the this keyword is bound to. In your method, by setting it to NULL it will either not have a this variable binding or it will be bound to the function itself or the window.
Since you're not using any variables or functions that are accessed via this, then there's no need to use the call method ... you can just use sum(3,4)
As stated in, for example, MDN, the first argument is
The value of this provided for the call to [the method]. Note that
this may not be the actual value seen by the method: if the method is
a function in non-strict mode code, null and undefined will be
replaced with the global object, and primitive values will be boxed.
As the MDN explained.
thisArg
The value of this provided for the call to fun. Note that this may not
be the actual value seen by the method: if the method is a function
in non-strict mode code, null and undefined will be replaced with the
global object, and primitive values will be boxed.
Simply put it by a little code.
<script >
'use strict'
function fun() {
alert(this);
}
fun.call(null);
</script>
In the strict mode ,this is null. But in the not strict mode . this is window or global object.