In Node.js, the global object provides access to globally available variables and functions without needing imports. It solves the problem of the absence of the window object common in browsers.
Understanding how Node.js handles modules and global scope is fundamental to organizing code and avoiding common pitfalls.
Global Object in Node.js
Global Variables and Functions
global: Access or define global variables.
global.myVar = 100;
console.log(myVar); // Output: 100
globalThis: Standard way to refer to the global object across environments.
globalThis.myVar = 200;
console.log(myVar); // Output: 200
Built-in Objects
process: Provides information about the current process.
console.log(process.version); // Output: Node.js version
console.log(process.env.NODE_ENV); // Output: current environment
require(): Import modules.
const fs = require('fs');
Buffer: Handle binary data.
const buffer = Buffer.from('Hello');
console.log(buffer); // Output: <Buffer 48 65 6c 6c 6f>
Global Constants
console.log(NaN); // Output: NaN
console.log(Infinity); // Output: Infinity
console.log(undefined); // Output: undefined
Timer Functions
setTimeout() and setInterval(): Delay or repeat code execution.
setTimeout(() => {
console.log("Runs once after 2 seconds");
}, 2000);
setInterval(() => {
console.log("Runs every 2 seconds");
}, 2000);
console
Used for logging to the console.
console.log("Hello, World!"); // Output: Hello, World!
console.error("This is an error!"); // Output: This is an error!
Node.js Module System
Where Do dirname and filename Come From?
In Node.js, dirname and filename are special variables automatically provided by the module system. They contain the absolute paths to the current module’s directory and file, respectively.
These are not part of the global object, but they are implicitly available in every module.
console.log(__dirname); // Output: Absolute path of current directory
console.log(__filename); // Output: Absolute path of current file
Why Don’t Variables Automatically Become Global?
In contrast to the browser’s window object, Node.js does not automatically make variables global. Each module in Node.js has its own isolated scope.
This prevents conflicts between different modules’ variables, which would otherwise lead to unintended behavior.
// In browser
let v = 3;
console.log(window.v); // Output: 3
// In Node.js
let v = 3;
console.log(global.v); // Output: undefined
Where Does module Come From?
The module object is automatically created for every file in Node.js. It contains metadata about the module, including exports, filename, and others.
When you call console.log(module), it outputs the details of the current module, including its exports object, which holds what the module is exporting.
How Node.js Solves the Global Scope Problem
In vanilla JavaScript, variables in different scripts can overlap in the global scope, causing conflicts:
// test.js
var a = 7;
// test1.js
var b = 9;
console.log(a + b); // Output: 16
In an HTML file, if both scripts are included, the global scope is shared, and the result is 16 because the variables are not encapsulated.
Node.js solves this by wrapping each file/module in an Immediately Invoked Function Expression (IIFE). This keeps variables isolated within their own scope, preventing conflicts.
(function(exports, require, module, __filename, __dirname) {
// Your module code here
return module.exports;
});
This wrapper function is automatically applied to every module, providing the special variables (exports, require, module, filename, dirname) and keeping the module’s variables private.
Node.js Module Example
In Node.js, when you require a module, its code is executed, and the module’s exports object is returned. Here’s how you encapsulate a module:
// people.js
var people = ["John", "Jane"];
module.exports = { people };
// index.js
const people = require("./people");
console.log(people); // Output: { people: ['John', 'Jane'] }
You manually export data with module.exports to make it available for other files to use.
exports and module.exports
The exports object is initialized as an empty object. To expose variables or functions from a module, you can assign them to module.exports.
// people.js
var people = ["John", "Jane"];
module.exports = { people };
// index.js
const people = require("./people");
console.log(people); // Output: { people: ['John', 'Jane'] }
By default, exports is empty, but when you assign values to module.exports, they are shared across files.
Different Export Styles
// Export a single function
module.exports = function greet(name) {
console.log(`Hello, ${name}!`);
};
// Export multiple items
module.exports = {
add: (a, b) => a + b,
subtract: (a, b) => a - b
};
// Or using exports shorthand
exports.add = (a, b) => a + b;
exports.subtract = (a, b) => a - b;
Important note: You can add properties to exports, but you cannot reassign it. Always reassign module.exports if you want to export a single value.
// This works
exports.myFunc = () => {};
// This does NOT work (breaks the reference)
exports = { myFunc: () => {} };
// Use this instead
module.exports = { myFunc: () => {} };
How require() Works
When you require a module:
- Node.js resolves the module path
- Checks if the module is already cached
- If not cached, reads the file
- Wraps it in the IIFE
- Executes the wrapped function
- Caches the result
- Returns module.exports
This means modules are only executed once, even if required multiple times. Subsequent requires return the cached exports.
// counter.js
let count = 0;
module.exports = {
increment() { count++; },
getCount() { return count; }
};
// main.js
const counter1 = require('./counter');
const counter2 = require('./counter');
counter1.increment();
console.log(counter2.getCount()); // Output: 1 (same instance)
Module Caching
Modules are cached after the first time they are loaded. This means the module code is only executed once, and subsequent requires return the cached module.exports.
// config.js
console.log("Config loaded");
module.exports = { apiKey: "secret" };
// main.js
const config1 = require('./config'); // Logs: "Config loaded"
const config2 = require('./config'); // No log (cached)
console.log(config1 === config2); // true (same object)
Summary
Node.js’s module system uses encapsulation to ensure each file/module has its own isolated scope, avoiding global conflicts. The require() function is used to load modules, and module.exports controls what a module exposes.
| Feature | Browser | Node.js |
|---|---|---|
| Global Object | window | global/globalThis |
| Module System | ES Modules | CommonJS |
| Variable Scope | Global by default | Module-scoped |
| Special Variables | None | dirname, filename, module, exports, require |
Understanding Node.js modules is essential for organizing code, managing dependencies, and building maintainable applications. The module system’s encapsulation prevents the common pitfalls of global scope pollution that plague browser JavaScript.