Object Creation Patterns

JavaScript offers several patterns for creating and organizing objects. Each pattern has its own use cases and trade-offs.

Factory Pattern

// Simple factory function
function createUser(name, age) {
  return {
    name,
    age,
    greet() {
      return `Hello, I'm ${this.name}`;
    }
  };
}

const user1 = createUser('John', 30);
const user2 = createUser('Jane', 25);

// Factory with private variables
function createCounter() {
  let count = 0;  // Private variable
  
  return {
    increment() { return ++count; },
    decrement() { return --count; },
    getCount() { return count; }
  };
}

Constructor Pattern

// Constructor function
function User(name, age) {
  this.name = name;
  this.age = age;
}

User.prototype.greet = function() {
  return `Hello, I'm ${this.name}`;
};

const user = new User('John', 30);

// Adding methods after creation
User.prototype.birthday = function() {
  this.age++;
};

// ES6 Class syntax (same under the hood)
class UserClass {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  
  greet() {
    return `Hello, I'm ${this.name}`;
  }
}

Singleton Pattern

// Classic Singleton
const Database = (function() {
  let instance;
  
  function createInstance() {
    return {
      data: [],
      add(item) { this.data.push(item); },
      remove(item) { /* ... */ }
    };
  }
  
  return {
    getInstance() {
      if (!instance) {
        instance = createInstance();
      }
      return instance;
    }
  };
})();

// Usage
const db1 = Database.getInstance();
const db2 = Database.getInstance();
console.log(db1 === db2); // true

Module Pattern

// IIFE Module
const Calculator = (function() {
  // Private variables
  let result = 0;
  
  // Private function
  function validate(num) {
    return typeof num === 'number';
  }
  
  // Public API
  return {
    add(num) {
      if (validate(num)) result += num;
      return result;
    },
    subtract(num) {
      if (validate(num)) result -= num;
      return result;
    },
    getResult() {
      return result;
    }
  };
})();

Common Interview Follow-up Questions

  1. What are the advantages of factory vs constructor pattern?
  2. How does prototypal inheritance work with these patterns?
  3. When would you use the Singleton pattern?
  4. How do you implement private properties in classes?

Best Practices

  • Choose patterns based on specific needs
  • Consider memory usage with prototypes
  • Use modern class syntax when appropriate
  • Implement proper encapsulation
  • Keep objects focused and single-purpose