DEV Community

Cover image for Which "this" is This in a Node Module?
Jake Witcher
Jake Witcher

Posted on

Which "this" is This in a Node Module?

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>
Enter fullscreen mode Exit fullscreen mode

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()
Enter fullscreen mode Exit fullscreen mode

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()
Enter fullscreen mode Exit fullscreen mode

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()
Enter fullscreen mode Exit fullscreen mode

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()
Enter fullscreen mode Exit fullscreen mode

Running the above code will print "implicitly bound context" and "explicitly bound context" to the console but not "default global context".

Top comments (0)