You can look at the loader code yourself here. Where the this
value for a module is set is actually here.
I can't say why they decided it should be the exports
object rather than module
object. Perhaps because that's what they expect you to assign to and it's certainly more common to reference exports
than it is module
.
Both the module
object and the exports
objects are passed as an argument to the wrapper and are in scope for your code so you can reference either one without using this
and, in my opinion, it makes for clearer code to use module
or module.exports
directly rather than using this
.
Here's a copy of the relevant code from the above link. The this
value is set in the ReflectApply()
call near the bottom of this block in the variable named thisValue
.
// Run the file contents in the correct scope or sandbox. Expose
// the correct helper variables (require, module, exports) to
// the file.
// Returns exception, if any.
Module.prototype._compile = function(content, filename) {
let moduleURL;
let redirects;
if (policy?.manifest) {
moduleURL = pathToFileURL(filename);
redirects = policy.manifest.getDependencyMapper(moduleURL);
policy.manifest.assertIntegrity(moduleURL, content);
}
maybeCacheSourceMap(filename, content, this);
const compiledWrapper = wrapSafe(filename, content, this);
let inspectorWrapper = null;
if (getOptionValue('--inspect-brk') && process._eval == null) {
if (!resolvedArgv) {
// We enter the repl if we're not given a filename argument.
if (process.argv[1]) {
try {
resolvedArgv = Module._resolveFilename(process.argv[1], null, false);
} catch {
// We only expect this codepath to be reached in the case of a
// preloaded module (it will fail earlier with the main entry)
assert(ArrayIsArray(getOptionValue('--require')));
}
} else {
resolvedArgv = 'repl';
}
}
// Set breakpoint on module start
if (resolvedArgv && !hasPausedEntry && filename === resolvedArgv) {
hasPausedEntry = true;
inspectorWrapper = internalBinding('inspector').callAndPauseOnStart;
}
}
const dirname = path.dirname(filename);
const require = makeRequireFunction(this, redirects);
let result;
const exports = this.exports;
const thisValue = exports;
const module = this;
if (requireDepth === 0) statCache = new SafeMap();
if (inspectorWrapper) {
result = inspectorWrapper(compiledWrapper, thisValue, exports,
require, module, filename, dirname);
} else {
result = ReflectApply(compiledWrapper, thisValue,
[exports, require, module, filename, dirname]);
}
hasLoadedAnyUserCJSModule = true;
if (requireDepth === 0) statCache = null;
return result;
};