How does the "this" keyword work?
I have noticed that there doesn't appear to be a clear explanation of what the this
keyword is and how it is correctly (and incorrectly) used in JavaScript on the Stack Overflow site.
I have witnessed some very strange behaviour with it and have failed to understand why it has occurred.
How does this
work and when should it be used?
I recommend reading Mike West's article Scope in JavaScript (mirror) first. It is an excellent, friendly introduction to the concepts of this
and scope chains in JavaScript.
Once you start getting used to this
, the rules are actually pretty simple. The ECMAScript Standard defines this
as a keyword that:
evaluates to the value of the ThisBinding of the current execution context;
(§11.1.1). ThisBinding is something that the JavaScript interpreter maintains as it evaluates JavaScript code, like a special CPU register which holds a reference to an object. The interpreter updates the ThisBinding whenever establishing an execution context in one of only three different cases:
Initial global execution context
This is the case for JavaScript code that is evaluated when a <script>
element is encountered:
<script type="text/javascript">//<![CDATA[
alert("I'm evaluated in the initial global execution context!");
setTimeout(function () {
alert("I'm NOT evaluated in the initial global execution context.");
}, 1);
//]]></script>
When evaluating code in the initial global execution context, ThisBinding is set to the global object, window
(§10.4.1.1).
Entering eval code
... by a direct call to eval()
ThisBinding is left unchanged; it is the same value as the ThisBinding of the calling execution context (§10.4.2(2)(a)).
... if not by a direct call to eval()
ThisBinding is set to the global object as if executing in the initial global execution context (§10.4.2(1)).
§15.1.2.1.1 defines what a direct call to eval()
is. Basically, eval(...)
is a direct call whereas something like (0, eval)(...)
or var indirectEval = eval; indirectEval(...);
var indirectEval = eval; indirectEval(...);
is an indirect call to eval()
. See chuckj's answer to (1,eval)('this') vs eval('this') in JavaScript? and this blog post by Dmitry Soshnikov for when you might use an indirect eval()
call.
Entering function code
This occurs when calling a function. If a function is called on an object, such as in obj.myMethod()
or the equivalent obj["myMethod"]()
, then ThisBinding is set to the object ( obj
in the example; §13.2.1). In most other cases, ThisBinding is set to the global object (§10.4.3).
The reason for writing "in most other cases" is because there are eight ECMAScript 5 built-in functions that allow ThisBinding to be specified in the arguments list. These special functions take a so-called thisArg
which becomes the ThisBinding when calling the function (§10.4.3).
These special built-in functions are:
Function.prototype.apply( thisArg, argArray )
Function.prototype.call( thisArg [ , arg1 [ , arg2, ... ] ] )
Function.prototype.bind( thisArg [ , arg1 [ , arg2, ... ] ] )
Array.prototype.every( callbackfn [ , thisArg ] )
Array.prototype.some( callbackfn [ , thisArg ] )
Array.prototype.forEach( callbackfn [ , thisArg ] )
Array.prototype.map( callbackfn [ , thisArg ] )
Array.prototype.filter( callbackfn [ , thisArg ] )
In the case of the Function.prototype
functions, they are called on a function object, but rather than setting ThisBinding to the function object, ThisBinding is set to the thisArg
.
In the case of the Array.prototype
functions, the given callbackfn is called in an execution context where ThisBinding is set to thisArg
if supplied; otherwise, to the global object.
Those are the rules for plain JavaScript. When you begin using JavaScript libraries (eg jQuery), you may find that certain library functions manipulate the value of this
. The developers of those JavaScript libraries do this because it tends to support the most common use cases, and users of the library typically find this behavior to be more convenient. When passing callback functions referencing this
to library functions, you should refer to the documentation for any guarantees about what the value of this
is when the function is called.
If you are wondering how a JavaScript library manipulates the value of this
, the library is simply using one of the built-in JavaScript functions accepting a thisArg
. You, too, can write your own function taking a callback function and thisArg
:
function doWork(callbackfn, thisArg) {
//...
if (callbackfn != null) callbackfn.call(thisArg);
}
EDIT:
I forgot a special case. When constructing a new object via the new
operator, the JavaScript interpreter creates a new, empty object, sets some internal properties, and then calls the constructor function on the new object. Thus, when a function is called in a constructor context, the value of this
is the new object that the interpreter created:
function MyType() {
this.someData = "a string";
}
var instance = new MyType();
// Kind of like the following, but there are more steps involved:
// var instance = {};
// MyType.call(instance);
QUIZ: Just for fun, test your understanding with the following examples.
To reveal the answers, mouse over the light yellow boxes.
What is the value of this
at line A? Why?
<script type="text/javascript">
if (true) {
// Line A
}
</script>
window
Line A is evaluated in the initial global execution context.
What is the value of this
at line B when obj.staticFunction()
is executed? Why?
<script type="text/javascript">
var obj = {
someData: "a string"
};
function myFun() {
// Line B
}
obj.staticFunction = myFun;
obj.staticFunction();
</script>
obj
When calling a function on an object, ThisBinding is set to the object.
What is the value of this
at line C? Why?
<script type="text/javascript">
var obj = {
myMethod : function () {
// Line C
}
};
var myFun = obj.myMethod;
myFun();
</script>
window
In this example, the JavaScript interpreter enters function code, but because myFun
/ obj.myMethod
is not called on an object, ThisBinding is set to window
.
This is different from Python, in which accessing a method ( obj.myMethod
) creates a bound method object.
What is the value of this
at line D? Why?
<script type="text/javascript">
function myFun() {
// Line D
}
var obj = {
myMethod : function () {
eval("myFun()");
}
};
obj.myMethod();
</script>
window
This one was tricky. When evaluating the eval code, this
is obj
. However, in the eval code, myFun
is not called on an object, so ThisBinding is set to window
for the call.
What is the value of this
at line E?
<script type="text/javascript">
function myFun() {
// Line E
}
var obj = {
someData: "a string"
};
myFun.call(obj);
</script>
obj
The line myFun.call(obj);
is invoking the special built-in function Function.prototype.call()
, which accepts thisArg
as the first argument.
The this
keyword behaves differently in JavaScript compared to other language. In Object Oriented languages, the this
keyword refers to the current instance of the class. In JavaScript the value of this
is determined mostly by the invocation context of function ( context.function()
) and where it is called.
1. When used in global context
When you use this
in global context, it is bound to global object ( window
in browser)
document.write(this); //[object Window]
When you use this
inside a function defined in the global context, this
is still bound to global object since the function is actually made a method of global context.
function f1()
{
return this;
}
document.write(f1()); //[object Window]
Above f1
is made a method of global object. Thus we can also call it on window
object as follows:
function f()
{
return this;
}
document.write(window.f()); //[object Window]
2. When used inside object method
When you use this
keyword inside an object method, this
is bound to the "immediate" enclosing object.
var obj = {
name: "obj",
f: function () {
return this + ":" + this.name;
}
};
document.write(obj.f()); //[object Object]:obj
Above I have put the word immediate in double quotes. It is to make the point that if you nest the object inside another object, then this
is bound to the immediate parent.
var obj = {
name: "obj1",
nestedobj: {
name:"nestedobj",
f: function () {
return this + ":" + this.name;
}
}
}
document.write(obj.nestedobj.f()); //[object Object]:nestedobj
Even if you add function explicitly to the object as a method, it still follows above rules, that is this
still points to the immediate parent object.
var obj1 = {
name: "obj1",
}
function returnName() {
return this + ":" + this.name;
}
obj1.f = returnName; //add method to object
document.write(obj1.f()); //[object Object]:obj1
3. When invoking context-less function
When you use this
inside function that is invoked without any context (ie not on any object), it is bound to the global object ( window
in browser)(even if the function is defined inside the object) .
var context = "global";
var obj = {
context: "object",
method: function () {
function f() {
var context = "function";
return this + ":" +this.context;
};
return f(); //invoked without context
}
};
document.write(obj.method()); //[object Window]:global
Trying it all with functions
We can try above points with functions too. However there are some differences.
this
. to specify them. new
operator. Below I tried out all the things that we did with Object and this
above, but by first creating function instead of directly writing an object.
/*********************************************************************
1. When you add variable to the function using this keyword, it
gets added to the function prototype, thus allowing all function
instances to have their own copy of the variables added.
*********************************************************************/
function functionDef()
{
this.name = "ObjDefinition";
this.getName = function(){
return this+":"+this.name;
}
}
obj1 = new functionDef();
document.write(obj1.getName() + "<br />"); //[object Object]:ObjDefinition
/*********************************************************************
2. Members explicitly added to the function protorype also behave
as above: all function instances have their own copy of the
variable added.
*********************************************************************/
functionDef.prototype.version = 1;
functionDef.prototype.getVersion = function(){
return "v"+this.version; //see how this.version refers to the
//version variable added through
//prototype
}
document.write(obj1.getVersion() + "<br />"); //v1
/*********************************************************************
3. Illustrating that the function variables added by both above
ways have their own copies across function instances
*********************************************************************/
functionDef.prototype.incrementVersion = function(){
this.version = this.version + 1;
}
var obj2 = new functionDef();
document.write(obj2.getVersion() + "<br />"); //v1
obj2.incrementVersion(); //incrementing version in obj2
//does not affect obj1 version
document.write(obj2.getVersion() + "<br />"); //v2
document.write(obj1.getVersion() + "<br />"); //v1
/*********************************************************************
4. `this` keyword refers to the immediate parent object. If you
nest the object through function prototype, then `this` inside
object refers to the nested object not the function instance
*********************************************************************/
functionDef.prototype.nestedObj = { name: 'nestedObj',
getName1 : function(){
return this+":"+this.name;
}
};
document.write(obj2.nestedObj.getName1() + "<br />"); //[object Object]:nestedObj
/*********************************************************************
5. If the method is on an object's prototype chain, `this` refers
to the object the method was called on, as if the method was on
the object.
*********************************************************************/
var ProtoObj = { fun: function () { return this.a } };
var obj3 = Object.create(ProtoObj); //creating an object setting ProtoObj
//as its prototype
obj3.a = 999; //adding instance member to obj3
document.write(obj3.fun()+"<br />");//999
//calling obj3.fun() makes
//ProtoObj.fun() to access obj3.a as
//if fun() is defined on obj3
4. When used inside constructor function .
When the function is used as a constructor (that is when it is called with new
keyword), this
inside function body points to the new object being constructed.
var myname = "global context";
function SimpleFun()
{
this.myname = "simple function";
}
var obj1 = new SimpleFun(); //adds myname to obj1
//1. `new` causes `this` inside the SimpleFun() to point to the
// object being constructed thus adding any member
// created inside SimipleFun() using this.membername to the
// object being constructed
//2. And by default `new` makes function to return newly
// constructed object if no explicit return value is specified
document.write(obj1.myname); //simple function
5. When used inside function defined on prototype chain
If the method is on an object's prototype chain, this
inside such method refers to the object the method was called on, as if the method is defined on the object.
var ProtoObj = {
fun: function () {
return this.a;
}
};
//Object.create() creates object with ProtoObj as its
//prototype and assigns it to obj3, thus making fun()
//to be the method on its prototype chain
var obj3 = Object.create(ProtoObj);
obj3.a = 999;
document.write(obj3.fun()); //999
//Notice that fun() is defined on obj3's prototype but
//`this.a` inside fun() retrieves obj3.a
6. Inside call(), apply() and bind() functions
Function.prototype
. this
which will be used while the function is being executed. They also take any parameters to be passed to the original function when it is invoked. fun.apply(obj1 [, argsArray])
Sets obj1
as the value of this
inside fun()
and calls fun()
passing elements of argsArray
as its arguments. fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
- Sets obj1
as the value of this
inside fun()
and calls fun()
passing arg1, arg2, arg3, ...
as its arguments. fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
- Returns the reference to the function fun
with this
inside fun bound to obj1
and parameters of fun
bound to the parameters specified arg1, arg2, arg3,...
. apply
, call
and bind
must have become apparent. apply
allows to specify the arguments to function as array-like object ie an object with a numeric length
property and corresponding non-negative integer properties. Whereas call
allows to specify the arguments to the function directly. Both apply
and call
immediately invokes the function in the specified context and with the specified arguments. On the other hand, bind
simply returns the function bound to the specified this
value and the arguments. We can capture the reference to this returned function by assigning it to a variable and later we can call it any time. function add(inc1, inc2)
{
return this.a + inc1 + inc2;
}
var o = { a : 4 };
document.write(add.call(o, 5, 6)+"<br />"); //15
//above add.call(o,5,6) sets `this` inside
//add() to `o` and calls add() resulting:
// this.a + inc1 + inc2 =
// `o.a` i.e. 4 + 5 + 6 = 15
document.write(add.apply(o, [5, 6]) + "<br />"); //15
// `o.a` i.e. 4 + 5 + 6 = 15
var g = add.bind(o, 5, 6); //g: `o.a` i.e. 4 + 5 + 6
document.write(g()+"<br />"); //15
var h = add.bind(o, 5); //h: `o.a` i.e. 4 + 5 + ?
document.write(h(6) + "<br />"); //15
// 4 + 5 + 6 = 15
document.write(h() + "<br />"); //NaN
//no parameter is passed to h()
//thus inc2 inside add() is `undefined`
//4 + 5 + undefined = NaN</code>
7. this
inside event handlers
this
directly inside event handling function refers to the corresponding element. Such direct function assignment can be done using addeventListener
method or through the traditional event registration methods like onclick
. this
directly inside the event property (like <button onclick="...this..." >
) of the element, it refers to the element. this
indirectly through the other function called inside the event handling function or event property resolves to the global object window
. attachEvent
. Instead of assigning the function to the event handler (and the thus making the function method of the element), it calls the function on the event (effectively calling it in global context). I recommend to better try this in JSFiddle.
<script>
function clickedMe() {
alert(this + " : " + this.tagName + " : " + this.id);
}
document.getElementById("button1").addEventListener("click", clickedMe, false);
document.getElementById("button2").onclick = clickedMe;
document.getElementById("button5").attachEvent('onclick', clickedMe);
</script>
<h3>Using `this` "directly" inside event handler or event property</h3>
<button id="button1">click() "assigned" using addEventListner() </button><br />
<button id="button2">click() "assigned" using click() </button><br />
<button id="button3" onclick="alert(this+ ' : ' + this.tagName + ' : ' + this.id);">used `this` directly in click event property</button>
<h3>Using `this` "indirectly" inside event handler or event property</h3>
<button onclick="alert((function(){return this + ' : ' + this.tagName + ' : ' + this.id;})());">`this` used indirectly, inside function <br /> defined & called inside event property</button><br />
<button id="button4" onclick="clickedMe()">`this` used indirectly, inside function <br /> called inside event property</button> <br />
IE only: <button id="button5">click() "attached" using attachEvent() </button>
Javascript's this
Simple function invocation
Consider the following function:
function foo() {
console.log("bar");
console.log(this);
}
foo(); // calling the function
Note that we are running this in the normal mode, ie strict mode is not used.
When run in a browser, the value of this
would be logged as window
. This is because window
is the global variable in a web browser's scope.
If you run this same piece of code in an environment like node.js, this
would refer to the global variable in your app.
Now if we run this in strict mode by adding the statement "use strict";
to the beginning of the function declaration, this
would no longer refer to the global variable in either of the envirnoments. This is done to avoid confusions in the strict mode. this
would, in this case just log undefined
, because that is what it is, it is not defined.
In the following cases, we would see how to manipulate the value of this
.
Calling a function on an object
There are different ways to do this. If you have called native methods in Javascript like forEach
and slice
, you should already know that the this
variable in that case refers to the Object
on which you called that function (Note that in javascript, just about everything is an Object
, including Array
s and Function
s). Take the following code for example.
var myObj = {key: "Obj"};
myObj.logThis = function () {
// I am a method
console.log(this);
}
myObj.logThis(); // myObj is logged
If an Object
contains a property which holds a Function
, the property is called a method. This method, when called, will always have it's this
variable set to the Object
it is associated with. This is true for both strict and non-strict modes.
Note that if a method is stored (or rather, copied) in another variable, the reference to this
is no longer preserved in the new variable. For example:
// continuing with the previous code snippet
var myVar = myObj.thisMethod;
myVar();
// logs either of window/global/undefined based on mode of operation
Considering a more commonly practical scenario:
var el = document.getElementById('idOfEl');
el.addEventListener('click', function() { console.log(this) });
// the function called by addEventListener contains this as the reference to the element
// so clicking on our element would log that element itself
The new
keyword
Consider a constructor function in Javascript:
function Person (name) {
this.name = name;
this.sayHello = function () {
console.log ("Hello", this);
}
}
var awal = new Person("Awal");
awal.sayHello();
// In `awal.sayHello`, `this` contains the reference to the variable `awal`
How does this work? Well, let's see what happens when we use the new
keyword.
new
keyword would immediately initialze an Object
of type Person
. Object
has its constructor set to Person
. Also, note that typeof awal
would return Object
only. Object
would be assigned the protoype of Person.prototype
. This means that any method or property in the Person
prototype would be available to all instances of Person
, including awal
. Person
itself is now invoked; this
being a reference to the newly constructed object awal
. Pretty straighforward, eh?
Note that the official ECMAScript spec no where states that such types of functions are actual constructor
functions. They are just normal functions, and new
can be used on any function. It's just that we use them as such, and so we call them as such only.
Calling functions on Functions : call
and apply
So yeah, since function
s are also Objects
(and in-fact first class variables in Javascript), even functions have methods which are... well, functions themselved.
All functions inherit from the global Function
, and two of its many methods are call
and apply
, and both can be used to manipulate the value of this
in the function on which they are called.
function foo () { console.log (this, arguments); }
var thisArg = {myObj: "is cool"};
foo.call(thisArg, 1, 2, 3);
This is a typical example of using call
. It basically takes the first parameter and sets this
in the function foo
as a reference to thisArg
. All other parameters passed to call
are passed to the function foo
as arguments.
So the above code will log {myObj: "is cool"}, [1, 2, 3]
in the console. Pretty nice way to change the value of this
in any function.
apply
is almost the same as call
accept that it takes only two parameters: thisArg
and an array which contains the arguments to be passed to the function. So the above call
call can be translated to apply
like this:
foo.apply(thisArg, [1,2,3])
Note that call
and apply
can override the value of this
set by dot method invocation we discussed in the second bullet. Simple enough :)
Presenting.... bind
!
bind
is a brother of call
and apply
. It is also a method inherited by all functions from the global Function
constructor in Javascript. The difference between bind
and call
/ apply
is that both call
and apply
will actually invoke the function. bind
, on the other hand, returns a new function with the thisArg
and arguments
pre-set. Let's take an example to better understand this:
function foo (a, b) {
console.log (this, arguments);
}
var thisArg = {myObj: "even more cool now"};
var bound = foo.bind(thisArg, 1, 2);
console.log (typeof bound); // logs `function`
console.log (bound);
/* logs `function () { native code }` */
bound(); // calling the function returned by `.bind`
// logs `{myObj: "even more cool now"}, [1, 2]`
See the difference between the three? It is subtle, but they are used differently. Like call
and apply
, bind
will also over-ride the value of this
set by dot-method invocation.
Also note that neither of these three functions do any change to the original function. call
and apply
would return the value from freshly constructed functions while bind
will return the freshly constructed function itself, ready to be called.
Extra stuff, copy this
Sometimes, you don't like the fact that this
changes with scope, specially nested scope. Take a look at the following example.
var myObj = {
hello: function () {
return "world"
},
myMethod: function () {
// copy this, variable names are case-sensitive
var that = this;
// callbacks ftw o/
foo.bar("args", function () {
// I want to call `hello` here
this.hello(); // error
// but `this` references to `foo` damn!
// oh wait we have a backup o/
that.hello(); // "world"
});
}
};
In the above code, we see that the value of this
changed with nested scope, but we wanted the value of this
from the original scope. So we 'copied' this
to that
and used the copy instead of this
. Clever, eh?
Index:
this
by default? new
keyword? this
with call
and apply
? bind
. this
to solve nested-scope issues. 上一篇: 如何用jQuery检查单选按钮?
下一篇: “this”关键字如何工作?