Understanding NodeJS scope and modules
NodeJS does not provide a global object which implicitly stores variables like window in the browser. In the browser the var x = "Hi"; whould implicitly bind x to window which another function may access.
These objects are available in all modules. Some of these objects aren't actually in the global scope but in the module scope - this will be noted.
The NodeJS documentation says. It further says on the global global object:
In browsers, the top-level scope is the global scope. This means that within the browser var something will define a new global variable. In Node.js this is different. The top-level scope is not the global scope; var something inside a Node.js module will be local to that module.
The NodeJS documentation on modules:
The module wrapper
Before a module's code is executed, Node.js will wrap it with a function wrapper that looks like the following:
(function(exports, require, module, __filename, __dirname) {
// Module code actually lives in here
});
By doing this, Node.js achieves a few things:
- It keeps top-level variables (defined with
var, const or let) scoped to the module rather than the global object.
- It helps to provide some global-looking variables that are actually specific to the module, such as:
- The
module and exports objects that the implementor can use to export values from the module.
- The convenience variables
__filename and __dirname, containing the module's absolute filename and directory path.
This is why you assign exports a value.
Solutions
Module factory
You should return a wrapper function that accepts a parameter providing it in any
foo.js:
// Export a function that establishes a new scope providing "x"
module.exports = function(x) {
return {
foo: function() {
console.log(x + 'foo'); // I want my module that require/import to pass into this file.
};
};
};
main.js:
var x = "Hi",
// call that factory function passing "x"
foo = require("./foo")(x).foo;
foo();
Note it uses module.exports since exports = ... alone would only replace the reference in the function parameter that NodeJS wraps around your module code (see the links above) whereas module.exports = ... replace the property of the exported module.
See the NodeJS docs on the difference:
It allows a shortcut, so that module.exports.f = ... can be written more succinctly as exports.f = .... However, be aware that like any variable, if a new value is assigned to exports, it is no longer bound to module.exports:
[...]
Assign x to global
This is only for completeness, don't do this.
- It will make it harder to understand where which references come from.
- You may accidentially overwrite other globals with the same name defined by other modules.
main.js:
var x = "Hi",
foo = require("./foo");
global.x = x;
foo();
Now x is defined on the global object and therefore "magically" available in any module.