Understanding which object context the keyword this
is referencing is one of the more confusing language features in JavaScript. Even if you have a firm understanding of the rules for this
binding there is still opportunity for it to surprise you, like when using this
in the outermost scope of a Node module.
For comparison purposes, let's see what happens when we use this
in the outermost scope of a script run in the browser before we try using it in a Node module.
<html>
<head>
<title>Which This Is This</title>
</head>
<body>
<script>
this.context = "is this the global context?"
function whichThisIsThis() {
alert(this.context)
}
whichThisIsThis()
</script>
</body>
</html>
Opening the above HTML in a browser creates an alert modal with the text "is this the global context?" displayed, confirming that both references to this
are for the same context object. If we replace this.context = ...
with window.context = ...
in the first line of the script we get the same text in the alert modal as before, confirming that this
is the window
object when whichThisIsThis
is executed.
Based on the above experiment in the browser, what do you think the following code will print to the console if executed by the Node runtime?
this.context = "is this the global context?"
function whichThisIsThis() {
console.log(this.context)
}
whichThisIsThis()
Surprisingly, it will print undefined
. Unlike in the browser script, this
in the outermost scope of a Node module is not a reference to the global object, rather it is a reference to the module.exports
object.
However when whichThisIsThis
is executed in the example above, this
inside the function's scope is the global object. Because the outermost scope is setting a context
property on the this
that's referencing module.exports
, we get an undefined response when trying to access a context
property on the this
that references the global object, the this
inside the whichThisIsThis
function scope.
You can test this out by changing this.context
in the call to console.log
to module.exports.context
. Run the code again and you should see the string value assigned to this.context
in the outermost scope print to the console.
this.context = "this is the module.exports context, not the global context!"
function whichThisIsThis() {
console.log(module.exports.context)
}
whichThisIsThis()
However if your intention is to use the global object you can keep this.context
as the argument for console.log
but you will need to explicitly create and set a context
property on the global object.
global.context = "this is the global context!"
function whichThisIsThis() {
console.log(this.context)
}
whichThisIsThis()
Keep in mind that the this
in the whichThisIsThis
function is only referencing the global object in the above example because no other context has been provided. If this function were to be called in a way that implicitly or explicitly provided a different object to assume the role of this
, the outcome would be different.
global.context = "default global context"
function whichThisIsThis() {
console.log(this.context)
}
let implicitContext = {
context: "implicitly bound context",
whichThisIsThis
}
implicitContext.whichThisIsThis()
let explicitContext = whichThisIsThis.bind({context: "explicitly bound context"})
explicitContext()
Running the above code will print "implicitly bound context" and "explicitly bound context" to the console but not "default global context".
Top comments (0)