Meaning of "this" in node.js modules and functions
Here's a few fundamental facts you must understand to clarify the situation:
In the top-level code in a Node module,
this
is equivalent tomodule.exports
. That's the empty object you see.When you use
this
inside of a function, the value ofthis
is determined anew before each and every execution of the function, and its value is determined by how the function is executed. This means that two invocations of the exact same function object could have differentthis
values if the invocation mechanisms are different (e.g.aFunction()
vs.aFunction.call(newThis)
vs.emitter.addEventListener("someEvent", aFunction);
, etc.) In your case,aFunction()
in non-strict mode runs the function withthis
set to the global object.When JavaScript files are
require
d as Node modules, the Node engine runs the module code inside of a wrapper function. That module-wrapping function is invoked with athis
set tomodule.exports
. (Recall, above, a function may be run with an abitrarythis
value.)
Thus, you get different this
values because each this
resides inside a different function: the first is inside of the Node-created module-wrapper function and the second is inside of aFunction
.
To understand this, you need to understand that Node.js actually wraps your module code in to a function, like this
(function (exports, require, module, __filename, __dirname) {
var test = function(){
console.log('From test: ' + this);
};
console.log(this);
test();
});
Detailed explanation can be found in this answer.
Now, this wrapped function is actually invoked like this
var args = [self.exports, require, self, filename, dirname];
return compiledWrapper.apply(self.exports, args);
So, this
, at the module level, is actually the exports
object.
You can confirm that like this
console.log(this, this === module.exports);
// {} true
Summary:
In Javascript the value of this
is determined when a function is called. Not when a function is created. In nodeJS in the outermost scope of a module the value of this
is the current module.exports
object. When a function is called as a property of an object the value of this changes to the object it was called. You can remember this simply by the left-of-the-dot rule:
When a function is called you can determine the value of
this
by looking at the place of the function invocation. The object left of the dot is the value ofthis
. If there is no object left of the dot the value ofthis
is themodule.exports
object (window
in browsers).
caveats:
- This rule does not apply for
es2015
arrow function which don't have their own binding ofthis
. - The functions
call
,apply
, andbind
can bend the rules regarding thethis
value.
Example (NodeJS):
console.log(this); // {} , this === module.exports which is an empty object for now
module.exports.foo = 5;
console.log(this); // { foo:5 }
let obj = {
func1: function () { console.log(this); },
func2: () => { console.log(this); }
}
obj.func1(); // obj is left of the dot, so this is obj
obj.func2(); // arrow function don't have their own this
// binding, so this is module.exports, which is{ foo:5 }
Output: