The keyword this
refers to the value of the object that is bound to the
function at the time of its call, meaning that its value is different depending
on whether a function is called as a method, as a standalone function, or as a
constructor.
When a function is called, it creates an instance of the keyword this
behind
the scenes as a reference to the object that contains that function, giving
access to the properties and methods defined alongside it from within its scope.
Working with this
is similar in some ways to working with a variable declared
with const
. Like a constant, this
can't be removed and its value can't be
reassigned, but the methods and properties of the object that the this
keyword
contains can be altered.
Global binding
Outside a function or the context of an object, this
refers to the
globalThis
property, which is a reference to the global object in most
JavaScript environments. In the context of a script running in a web browser,
the global object is the window
object:
this;
> Window {0: Window, window: Window, self: Window, document: document, name: '', location: Location, ...}
In Node.js, globalThis
is the global
object:
$ node
Welcome to Node.js v20.10.0.
Type ".help" for more information.
> this
<ref *1> Object [global] {
...
}
Outside strict mode, this
also refers to the global object inside a standalone
function, because the parent Window
is the object that effectively "owns"
those functions.
function myFunction() {
console.log( this );
}
myFunction();
> Window {...}
(function() {
console.log( this );
}());
> Window {...}
When using strict mode, this
has a value of undefined
inside a standalone
function:
(function() {
"use strict";
console.log( this );
}());
> undefined
Before the introduction of strict mode, a null
or undefined
value for this
would be replaced by a reference to the global object. You might sometimes see
global binding referred to as "default binding" because of this legacy behavior.
Implicit binding
When a function is called as a method of an object, an instance of this
inside
that method refers to the object that contains the method, giving access to the
methods and properties that sit alongside it:
let myObject = {
myValue: "This is my string.",
myMethod() {
console.log( this.myValue );
}
};
myObject.myMethod();
> "This is my string."
It might look like the value of this
depends on how a function and its
enclosing object are defined. Instead, the context for the value of this
is
the current execution context. In this case, the execution context is that the
myObject
object is calling the myMethod
method, so myObject
is the value
for this
. This might seem like a technicality in the context of the previous
examples, but for more advanced uses of this
, it's an essential distinction to
keep in mind.
In general, use this
in ways that don't expect the surrounding code to have
any particular structure. The exception to this rule is ES5
Arrow functions.
this
in arrow functions
In arrow functions,
this
resolves to a binding in a
lexically enclosing environment. This means that
this
in an arrow function refers to the value of this
in that function's
closest enclosing context:
let myObject = {
myMethod() { console.log( this ); },
myArrowFunction: () => console.log( this ),
myEnclosingMethod: function () {
this.myArrowFunction = () => { console.log(this) };
}
};
myObject.myMethod();
> Object { myMethod: myMethod(), myArrowFunction: myArrowFunction() }
myObject.myArrowFunction();
> Window {...}
In the previous example, myObject.myMethod()
logs myObject
as the object
that "owns" that method, but myObject.myArrowFunction()
returns globalThis
(or undefined
), because the instance of this
inside the arrow function
refers instead to the highest enclosing scope.
In the following example, myEnclosingMethod
creates an arrow function on the
object that contains it when it's executed. The instance of this
inside the
arrow function now refers to the value of this
inside the enclosing
environment, which is the method that contains that arrow function. Because the
value of this
inside myEnclosingMethod
refers to myObject
, after you
define the arrow function, this
inside the arrow function also refers to
myObject
:
let myObject = {
myMethod() { console.log( this ); },
myEnclosingMethod: function () {
this.myArrowFunction = () => { console.log(this) };
}
};
myObject.myEnclosingMethod();
myObject.myArrowFunction();
> Object { myMethod: myMethod(), myArrowFunction: myArrowFunction() }
Explicit binding
Implicit binding handles most use cases for working with this
. However, you
might sometimes need the value of this
to represent a specific execution
context, instead of the assumed context. An illustrative, if slightly outdated,
example is working with this
within the callback function of a setTimeout
,
because this callback has a unique execution context:
var myObject = {
myString: "This is my string.",
myMethod() {
console.log( this.myString );
}
};
myObject.myMethod();
> "This is my string."
setTimeout( myObject.myMethod, 100 );
> undefined
Although this specific shortcoming of setTimeout
has since been addressed by
other features, similar issues of "losing" this
have previously been addressed
by creating an explicit reference to the value of this
within the scope of the
intended context. You might occasionally see instances of this
being assigned
to a variable using identifiers like that
, self
, or _this
in legacy
codebases. These are common identifier conventions for variables containing a
passed this
value.
When you call a function using the call()
, bind()
, or apply()
methods,
this
explicitly references the object being called:
let myFunction = function() {
console.log( this.myValue );
}
let myObject = {
"myValue" : "This is my string."
};
myFunction.call( myObject );
> "This is my string."
var myObject = {
myString: "This is my string.",
myMethod() {
console.log( this.myString );
}
};
setTimeout( myObject.myMethod.bind( myObject ), 100 );
> "This is my string."
Explicit binding overrides the this
value provided by implicit binding.
let myObject = {
"myValue" : "This string sits alongside myMethod.",
myMethod() {
console.log( this.myValue );
}
};
let myOtherObject = {
"myValue" : "This is a string in another object entirely.",
};
myObject.myMethod.call( myOtherObject );
> "This is a string in another object entirely."
If a function is called in a way that would set the value of this
to
undefined
or null
, that value is replaced by globalThis
outside strict
mode:
let myFunction = function() {
console.log( this );
}
myFunction.call( null );
> Window {...}
Similarly, if a function is called in a way that would give this
a primitive
value, that value is substituted with the
primitive value's wrapper object
outside strict mode:
let myFunction = function() {
console.log( this );
}
let myNumber = 10;
myFunction.call( myNumber );
> Number { 10 }
In strict mode, a passed this
value isn't coerced to an object in any way,
even if it's a primitive, null
, or undefined
value:
"use strict";
let myFunction = function() {
console.log( this );
}
let myNumber = 10;
myFunction.call( myNumber );
> 10
myFunction.call( null );
> null
new
binding
When a class is used as a constructor using the
new
keyword, this
refers to the newly-created instance:
class MyClass {
myString;
constructor() {
this.myString = "My string.";
}
logThis() {
console.log( this );
}
}
const thisClass = new MyClass();
thisClass.logThis();
> Object { myString: "My string." }
Similarly, the value of this
inside a constructor function called using new
refers to the object being created:
function MyFunction() {
this.myString = "My string.";
this.logThis = function() {
console.log( this );
}
}
const myObject = new MyFunction();
myObject.logThis();
> Object { myString: "My string.", logThis: logThis() }
Event handler binding
In the context of event handlers, the value of this
references the object that
invokes it. Inside an event handler's callback function, that means this
references the element associated with the handler:
let button = document.querySelector( "button" );
button.addEventListener( "click", function( event ) { console.log( this ); } );
When a user interacts with the button
in the previous snippet, the result is
the element object containing the <button>
itself:
> Button {}
When an arrow function is used as an event listener callback, the value of
this
is again provided by the closest enclosing execution context. At the top
level, that means this
inside an event handler callback function is
globalThis
:
let button = document.querySelector( "button" );
button.addEventListener( "click", ( event ) => { console.log( this ); } );
> undefined
As with any other object, when you use the call()
, bind()
, or apply()
methods to reference the callback function of an event listener, this
references the object explicitly:
let button = document.querySelector( "button" );
let myObject = {
"myValue" : true
};
function handleClick() {
console.log( this );
}
button.addEventListener( "click", handleClick.bind( myObject ) );
> Object { myValue: true }
Check your understanding
For a script running in a web browser, what is the global object
that this
refers to when used outside a function or the
context of an object?
undefined
objectwindow
objectbrowser
object