Class in JavaScript was so weird and we can accidently broke our code easily, then I found an article that explain an idea about pattern that can be an alternative for JavaScript Class for some cases, it called Ice Factory Pattern that founded by Bill Sourour

Basically, the idea of class are simple, it just a way to organize or grouping some function / method into single Object, and it can be extends or inherits. But ...

Class in JavaScript behave quite differently from Object-Centric language that you already know like Java or C#, if you are not carefully it will bite you.

so for example if we wanna make a Cart class in JavaScript will looks like this

class Cart {
  constructor(db){
    this.db = db;
  }
  
  add(item){
    this.db.items.insert(item);
  }
  
  remove(item){
    this.db.items.remove(item);
  }
  
  get(){
    return this.db.items;
  }
}

// in other module
const db = require('db');
const cart = new Cart(db);
db.add({
  id: 1,
  name: 'title',
  price: 99.9,
});

Perhaps you was though this looks nice, but unfortunately the new keyword was mutable, so you can re-assign the methods!

const db = require('db');
const cart = new Cart(db);

cart.add = () => console.log('you have been hacked!');
db.add({
  id: 1,
  name: 'title',
  price: 99.9,
}); // output "you have been hacked!"

Even worse, objects created using the new keyword inherit the prototype of the class that was used to create them. So, changes to a class’ prototype affect all objects created from that class — even if a change is made after the object was created!

Using Ice Factory Pattern

because that was just a group of function / method, how if we just literally return that object using closure but freezed?

export default const makeCart = db => {
  function add(item) {
    db.items.insert(item);
  }
  
  function remove(item) {
    db.items.remove(item);
  }
  
  function get() {
    return db.items;
  }
  
  return Object.freeze({
    add,
    remove,
    get,
  });
}

// in other module
const db = require('db');
const cart = makeCart(db);
cart.add({ 
  id: 1,
  name: 'foo', 
  price: 9.99
});

Now the cart object completely immutable, we don't need this and new anymore!

Privacy

with this pattern we can also make some private method

export default const makeCart = db => {
  const secret = () => {
    return `secretword`;
  }
  
  const get = secretWord => {
    if (secretWord === secret())
      return db.items;
  }
  
  return Object.freeze({
    get,
  });
}

So what do you think? is there any project that you need to implement this pattern? but remember, it just an alternative for Class, it can't completely replace Class in all cases.

Thanks for reading!