javascript

examples

examples.js⚔
// ============================================================================
// 14.1 Module Systems Overview - Examples
// ============================================================================
// This file demonstrates the evolution of JavaScript module systems
// from early patterns to modern ES Modules.

// ============================================================================
// 1. THE PROBLEM: Global Namespace Pollution (Before Modules)
// ============================================================================

// In early JavaScript, all code shared the global namespace
// This led to naming conflicts and maintenance nightmares

// file1.js
var userName = 'Alice';
function greet() {
  console.log('Hello from file1!');
}

// file2.js (loaded after file1.js)
var userName = 'Bob'; // Overwrites file1's userName!
function greet() {
  // Overwrites file1's greet!
  console.log('Hello from file2!');
}

// Result: Only file2's values exist - file1's are lost!
console.log('Example 1 - Global pollution:', userName); // "Bob"

// ============================================================================
// 2. SOLUTION 1: Namespace Pattern (2000s)
// ============================================================================

// Wrap everything in a single global object
var MyApp = MyApp || {};

MyApp.utils = {
  formatDate: function (date) {
    return date.toISOString().split('T')[0];
  },
  capitalize: function (str) {
    return str.charAt(0).toUpperCase() + str.slice(1);
  },
};

MyApp.models = {
  User: function (name) {
    this.name = name;
  },
};

// Usage
console.log('Example 2 - Namespace pattern:');
console.log(MyApp.utils.formatDate(new Date()));
console.log(MyApp.utils.capitalize('hello'));

// ============================================================================
// 3. SOLUTION 2: IIFE Module Pattern (2005+)
// ============================================================================

// Immediately Invoked Function Expression creates private scope
var CounterModule = (function () {
  // Private variables - not accessible outside
  var count = 0;
  var history = [];

  // Private function
  function log(action) {
    history.push({ action: action, count: count, time: new Date() });
  }

  // Public API (revealed)
  return {
    increment: function () {
      count++;
      log('increment');
      return count;
    },
    decrement: function () {
      count--;
      log('decrement');
      return count;
    },
    getCount: function () {
      return count;
    },
    getHistory: function () {
      return [...history]; // Return copy to protect internal state
    },
  };
})();

console.log('\nExample 3 - IIFE Module Pattern:');
console.log('Initial count:', CounterModule.getCount()); // 0
CounterModule.increment();
CounterModule.increment();
CounterModule.decrement();
console.log('After operations:', CounterModule.getCount()); // 1
console.log('History:', CounterModule.getHistory());
// console.log(count); // ReferenceError - count is private!

// ============================================================================
// 4. SOLUTION 3: Revealing Module Pattern
// ============================================================================

var Calculator = (function () {
  // All functions defined as private first
  var result = 0;

  function add(x) {
    result += x;
    return this;
  }

  function subtract(x) {
    result -= x;
    return this;
  }

  function multiply(x) {
    result *= x;
    return this;
  }

  function divide(x) {
    if (x === 0) throw new Error('Division by zero');
    result /= x;
    return this;
  }

  function getResult() {
    return result;
  }

  function reset() {
    result = 0;
    return this;
  }

  // Reveal public pointers to private functions
  return {
    add: add,
    subtract: subtract,
    multiply: multiply,
    divide: divide,
    getResult: getResult,
    reset: reset,
  };
})();

console.log('\nExample 4 - Revealing Module Pattern:');
Calculator.reset().add(10).multiply(2).subtract(5);
console.log('Calculator result:', Calculator.getResult()); // 15

// ============================================================================
// 5. SOLUTION 4: Module with Dependencies
// ============================================================================

// Passing dependencies as parameters (early dependency injection)
var UserService = (function (storage, validator) {
  var users = storage.load('users') || [];

  return {
    addUser: function (user) {
      if (validator.isValidUser(user)) {
        users.push(user);
        storage.save('users', users);
        return true;
      }
      return false;
    },
    getUsers: function () {
      return [...users];
    },
  };
})(
  // Mock storage dependency
  {
    data: {},
    load: function (key) {
      return this.data[key];
    },
    save: function (key, value) {
      this.data[key] = value;
    },
  },
  // Mock validator dependency
  {
    isValidUser: function (user) {
      return user && user.name && user.email;
    },
  }
);

console.log('\nExample 5 - Module with Dependencies:');
UserService.addUser({ name: 'Alice', email: 'alice@example.com' });
UserService.addUser({ name: 'Bob', email: 'bob@example.com' });
console.log('Users:', UserService.getUsers());

// ============================================================================
// 6. COMMONJS PATTERN (Node.js style - simulated)
// ============================================================================

// In Node.js, each file is a module with its own scope
// This is a simulation of how CommonJS works

// Simulated module system
var CommonJSSimulator = (function () {
  var modules = {};
  var cache = {};

  function define(name, factory) {
    modules[name] = factory;
  }

  function require(name) {
    if (cache[name]) {
      return cache[name].exports;
    }

    var module = { exports: {} };
    cache[name] = module;

    modules[name](module, module.exports, require);
    return module.exports;
  }

  return { define: define, require: require };
})();

// Define a module
CommonJSSimulator.define('math', function (module, exports, require) {
  exports.add = function (a, b) {
    return a + b;
  };
  exports.multiply = function (a, b) {
    return a * b;
  };
  exports.PI = 3.14159;
});

// Define another module that depends on math
CommonJSSimulator.define('circle', function (module, exports, require) {
  var math = require('math');

  exports.area = function (radius) {
    return math.PI * math.multiply(radius, radius);
  };

  exports.circumference = function (radius) {
    return 2 * math.PI * radius;
  };
});

// Use the modules
console.log('\nExample 6 - CommonJS Simulation:');
var circle = CommonJSSimulator.require('circle');
console.log('Circle area (r=5):', circle.area(5).toFixed(2));
console.log('Circle circumference (r=5):', circle.circumference(5).toFixed(2));

// ============================================================================
// 7. AMD PATTERN (RequireJS style - simulated)
// ============================================================================

// Asynchronous Module Definition - designed for browsers
var AMDSimulator = (function () {
  var modules = {};
  var definitions = {};

  function define(name, dependencies, factory) {
    definitions[name] = { deps: dependencies, factory: factory };
  }

  function require(dependencies, callback) {
    var resolvedDeps = dependencies.map(function (dep) {
      return getModule(dep);
    });
    callback.apply(null, resolvedDeps);
  }

  function getModule(name) {
    if (modules[name]) return modules[name];

    var def = definitions[name];
    if (!def) throw new Error('Module not found: ' + name);

    var deps = def.deps.map(getModule);
    modules[name] = def.factory.apply(null, deps);
    return modules[name];
  }

  return { define: define, require: require };
})();

// Define modules AMD style
AMDSimulator.define('utils', [], function () {
  return {
    formatCurrency: function (amount) {
      return '$' + amount.toFixed(2);
    },
  };
});

AMDSimulator.define('product', ['utils'], function (utils) {
  function Product(name, price) {
    this.name = name;
    this.price = price;
  }

  Product.prototype.getFormattedPrice = function () {
    return utils.formatCurrency(this.price);
  };

  return Product;
});

// Use AMD modules
console.log('\nExample 7 - AMD Simulation:');
AMDSimulator.require(['product'], function (Product) {
  var laptop = new Product('Laptop', 999.99);
  console.log(laptop.name + ': ' + laptop.getFormattedPrice());
});

// ============================================================================
// 8. UMD PATTERN (Universal Module Definition)
// ============================================================================

// UMD works in both CommonJS and AMD environments
(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD
    define(['dependency'], factory);
  } else if (typeof module === 'object' && module.exports) {
    // CommonJS
    module.exports = factory(require('dependency'));
  } else {
    // Browser globals
    root.MyLibrary = factory(root.Dependency);
  }
})(typeof self !== 'undefined' ? self : this, function (dependency) {
  // Library code here
  return {
    version: '1.0.0',
    greet: function (name) {
      return 'Hello, ' + name + '!';
    },
  };
});

console.log('\nExample 8 - UMD Pattern:');
console.log(
  'UMD pattern creates modules that work everywhere (AMD, CommonJS, Browser)'
);

// ============================================================================
// 9. ES MODULES PREVIEW (Modern Standard)
// ============================================================================

// ES Modules (ESM) are the official standard
// Note: This is just a demonstration of syntax - actual ESM requires
// file extensions and proper module context

console.log('\nExample 9 - ES Modules Syntax Preview:');
console.log(`
// math.js (ES Module)
export const PI = 3.14159;
export function add(a, b) { return a + b; }
export default class Calculator { ... }

// main.js
import Calculator, { PI, add } from './math.js';
import * as MathUtils from './math.js';

// Dynamic import
const module = await import('./math.js');
`);

// ============================================================================
// 10. MODULE SYSTEMS COMPARISON
// ============================================================================

console.log('\nExample 10 - Module Systems Comparison:');
console.log(`
ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¬ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”
│ System       │ Environment  │ Loading     │ Syntax             │
ā”œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¼ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”¤
│ IIFE         │ Browser      │ Script tags │ (function(){})()   │
│ CommonJS     │ Node.js      │ Synchronous │ require/exports    │
│ AMD          │ Browser      │ Async       │ define/require     │
│ UMD          │ Both         │ Both        │ Wrapper pattern    │
│ ES Modules   │ Both         │ Async       │ import/export      │
ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”“ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜
`);

// ============================================================================
// SUMMARY
// ============================================================================

console.log('\n=== Module Systems Evolution Summary ===');
console.log('1. Global scripts → Namespace pollution problems');
console.log('2. IIFE pattern → Encapsulation via closures');
console.log('3. CommonJS → Synchronous loading for Node.js');
console.log('4. AMD → Asynchronous loading for browsers');
console.log('5. UMD → Universal compatibility wrapper');
console.log('6. ES Modules → Official standard, best of both worlds');
Examples - JavaScript Tutorial | DeepML