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.
Related
var abc=(function(){
var self=this;
return {
self:self
}
})();
When doing abc.self I get undefined what does this happen to be in this context.
What you have can be simplified for the purpose of the explanation in
(function(){ console.log(this) })();
Your expression (in the first set of parenthesis) defines a function. You then call this function without context (the this). This construct is called an IIFE. As you don't pass a context, the behavior depends whether it is called in strict mode or not :
In non strict mode, you would have the global object (window in a browser, global in node).
In strict mode, a missing context of a function call isn't replaced, it's undefined.
As you get undefined, I guess you're in strict mode. You probably have "use strict"; at the start of the file or in an enclosing function.
If you wanted to pass a context, you might for example have done
(function(){ console.log(this) }).call(someobject);
in that "root scope" this is window
and
console.log(abc.self);
results for me in
Window {top: Window, window: Window, ...}
this refers to the current object. In your condition this will be window, and as you're trying to get the value abc.self, you need to use like this:
this.self = this;
Now, only you can get the value:
var xyz = new abc();
xyz.self
But to note, you cannot use abc as the constructor like above code because you are using the closure.
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);
I was expecting the 2nd call of the "taco" function to generate a runtime error since I am not calling it with the "this" keyword:
function foo() {
var bar = "baz";
this.taco = function() {
console.log(bar);
};
this.taco();
taco(); // I expected a runtime error here.
}
foo();
However, it does not.
Here is a fiddle of the same code: http://jsfiddle.net/phillipkregg/gdFxU/226/
Is JavaScript using some type of implicit context management here?
Just curious, thanks!
The reason is that when you call foo(), you are invoking it in the scope of the window object. That means that inside of foo(), the value of this is set to window.
Thus, this.taco() is actually window.taco() which is the same as taco(). In other words, taco() is a global function so it works either way you call it as taco(), as window.taco() or as this.taco() when this is window.
If you involve taco() as a new object like this where this is set to a new instance of foo and is not equal to window, then you get the expected run-time error:
function foo() {
var bar = "baz";
this.taco = function() {
console.log(this);
console.log(bar);
};
this.taco();
taco(); // I expected a runtime error here.
}
var x = new foo();
Example: http://jsfiddle.net/jfriend00/3LkxU/
If you are confused about the value of this, there are these javascript rules that determine the value of this:
If you call a function with new like x = new foo(), then a new instance of foo is created and the value of this is set to that object inside the foo() function and that new instance is returned from foo() by default.
If you call any function normally like foo(), then the value of this is set to be the global object which in a browser is window or if in javascript's newer "strict" mode, then this will be undefined. This is what was happening in your original example.
If you call a method with an object reference like obj.foo(), then this will be set to be the obj object.
If you make a function call with .apply() or .call(), then you can specifically control what the value of this is set to with the first argument to .apply() or .call(). For example: foo.call(obj) would call the foo() function and set the this pointer to the obj object.
If you are not in any function call (e.g. at the global scope), then this will be either the Global object (window in a browser) or undefined in strict mode.
As in all of the above rules, this is controlled by how the caller calls you, not how the function/method is defined.
The reason is this in foo(), when it's called just as is, will reference a global object. This means taco function will be introduced in the global scope.
To get the functionality you want use new foo() syntax instead. Then this will refer to a new object, which taco property will be assigned a new value (function). Calling taco directly will get you an error then.
foo(); // equals window.foo() , `this` equals `window` and `this.taco` equals `window.taco` and `window.taco` equals `taco` as it is global
new foo(); //creates a new object. this will give error because here `this.taco` is not `taco`
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.
I recently read somewhere (I am really sorry I can't provide the source) that you can use this.varname to access globals in replacement to window.varname to save 2 chars
var myVar = "global";
function myFunc() {
var myVar = "notGlobal";
alert( this.myVar ); //global
}
It seems to work, but I want to know if:
it is safe to use in old browsers
it is cross-browser compatible
it will fail under some weird circumstances
I don't think I'd do it, but it's completely cross-browser compatible if this is referring to the global object (window). Whether it is will depend on how the function in question was called (at global scope, this does indeed refer to the global object), and whether the code in question is in "strict mode" or not. (In strict mode, this does not refer to the global object. Kudos and upvotes to Esailija for pointing that out.)
In non-strict code:
So at global scope:
console.log(this === window); // true if not in strict mode
And similarly, if you have a function you call directly:
function foo() {
console.log(this === window);
}
foo(); // Logs "true"
But, in JavaScript, this is set entirely by how a function is called. So we could call foo setting this to something else:
var obj = {};
foo.call(obj); // Now it logs "false", `this` === `obj` during the call
Similarly:
var obj = {};
obj.f = foo;
obj.f(); // Also logs "false", `this` === `obj` during the call
So in conclusion, at global scope (not in any function call), yes, this is reliably pointing to the global object, and if you control how the function gets called and you call it without setting this to anything else (via call or apply, or by using it from an object property a'la obj.f above), then, again, it will reliably refer to the global object. This is covered by sections 10.4.1 (Entering Global Code) and 10.4.3 (Entering Function Code) of the specification. This is how it's been from the very beginning, I believe; certainly for the last 15 years, so you're unlikely to find a non-compliant environment.
More reading:
Mythical methods
You must remember this
It will not work in modern browsers if someone slaps "use strict" above your code as this will be undefined inside the function.
<script type="text/javascript">
"use strict";
...
function test(){
console.log(this);
}
test(); // undefined
</script>
Note that you can save much more characters just by assigning window to some variable at the top of your code and using that as it will be shortened to some one character variable by a minimizer.
(function(global){
global.foo();
global.bar();
})(window);
would be minimized to (without whitespace):
(function(a){
a.foo();
a.bar();
})(window);
Where as this would not be touched as it's a keyword.
this always has a value. And if this hasnt been overridden somehow, then it will be window where all your globals are.
It will work in all JS implementations, but beware! This is more brittle, and it won't always point to a global variable.
For instance:
var myVar = "global";
var obj = {
myVar: "property",
fn: function() { return this.myVar; }
}
console.log(obj.fn()); // "property"
This fails because in this context this is that object. But when executing a function that is NOT a property of an object, this will default to window, like your example.