Building a Basic JavaScript Module System
Creating a module system in JavaScript allows you to organize your code into reusable and maintainable units. This challenge asks you to implement a simplified module system that enables you to define, load, and use modules, promoting code organization and preventing namespace collisions. This is a fundamental concept in modern JavaScript development, especially when working with larger projects.
Problem Description
You are tasked with creating a rudimentary module system in JavaScript. The system should allow you to:
- Define Modules: Modules should be defined using a specific function (e.g.,
defineModule). This function should accept a module name and an object containing the module's exports. - Load Modules: A function (
loadModule) should be provided to retrieve a module by its name. This function should return the module's exports. - Module Storage: The module system should maintain a registry of defined modules, accessible internally.
- Error Handling: The
loadModulefunction should handle cases where a module has not been defined, returning an appropriate error message orundefined.
Key Requirements:
- The module system should not rely on any external libraries or frameworks.
- Modules should be encapsulated; their internal state should not be directly accessible from outside the module.
- The module system should prevent naming conflicts between modules.
Expected Behavior:
- When a module is defined, it should be stored in the module registry.
- When a module is loaded, the
loadModulefunction should return the module's exports. - Attempting to load a non-existent module should result in an error or
undefinedbeing returned.
Edge Cases to Consider:
- What happens if you try to define a module with the same name twice? (Should it overwrite the previous definition?)
- How should the module system handle circular dependencies (Module A depends on Module B, and Module B depends on Module A)? (For simplicity, you can assume circular dependencies won't be explicitly tested, but consider how your design might handle them.)
- What happens if the
defineModulefunction is called with invalid input (e.g., a module name that is not a string)?
Examples
Example 1:
Input:
defineModule('math', {
add: (a, b) => a + b,
subtract: (a, b) => a - b
});
Output:
{ add: [Function: add], subtract: [Function: subtract] }
Explanation: A module named 'math' is defined with two functions, 'add' and 'subtract'. The output is the exported object.
Example 2:
Input:
loadModule('math');
Output:
{ add: [Function: add], subtract: [Function: subtract] }
Explanation: The 'math' module is loaded, and its exports are returned.
Example 3:
Input:
loadModule('nonExistentModule');
Output:
undefined
Explanation: The 'nonExistentModule' has not been defined, so the function returns undefined.
Constraints
- The module system should be implemented using plain JavaScript (no external libraries).
- Module names should be strings.
- The
defineModulefunction should accept a module name and an object containing the module's exports. - The
loadModulefunction should accept a module name and return the module's exports orundefinedif the module is not found. - The module system should be reasonably efficient for a small number of modules (e.g., up to 100). Performance is not a primary concern for this challenge.
Notes
Consider using a simple object or Map to store the modules. Think about how to encapsulate the module registry to prevent external access. The goal is to create a basic, functional module system that demonstrates the core principles of modularity in JavaScript. You don't need to implement advanced features like dependency injection or asynchronous loading. Focus on the fundamental definition, storage, and retrieval of modules.