jpcasa
12/20/2018 - 2:13 PM

JS Encapsulation

Encapsulation means information hiding. It’s about hiding as much as possible of the object’s internal parts and exposing a minimal public interface.

Encapsulation in JS

Encapsulation means information hiding. It’s about hiding as much as possible of the object’s internal parts and exposing a minimal public interface. The simplest and most elegant way to create encapsulation in JavaScript is using closures. A closure can be created as a function with private state. When creating many closures sharing the same private state, we create an object.

Conclusion

JavaScript offers a unique way for creating encapsulated objects using factory functions. Objects encapsulate state.

// USING A FACTORY FUNCTION
function Stack(){
  let list = [];
  
  function push(value){ list.push(value); }
  function pop(){ return list.pop(); }
  
  return Object.freeze({
    push,
    pop
  });
}

let stack = Stack();
stack.push(1);
stack.push(2);
stack.push(3);
stack.pop(); //3
stack.pop(); //2

stack.list; //undefined
stack.list = 0;//Cannot add property list, object is not extensible
class Stack {
  constructor(){
    this.list = [];
  }
  
  push(value) { this.list.push(value); }
  pop() { return this.list.pop(); }
}

let stack = new Stack();
stack.push(1);
stack.push(2);
stack.list = 0; //corrupt the private state
console.log(stack.pop()); //this.list.pop is not a function
function Queue(){
  let list = [];
  
  function enqueue(value){ list.push(value); }
  function dequeue(){ return list.shift(); }
  
  return Object.freeze({
    enqueue,
    dequeue
  });
}

let queue = Queue();
queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3);
queue.dequeue(); //1
queue.dequeue(); //2

queue.list; //undefined
function EventEmitter(){
  let subscribers = [];
  
  function subscribe(type, callback){
    subscribers[type] = subscribers[type] || [];
    subscribers[type].push(callback); 
  }
  
  function notify(value, fn){
    try {
      fn(value);
    }
    catch(e) { console.error(e); }
  }
  
  function publish(type, value){
    if(subscribers[type]){
      let notifySubscriber = notify.bind(null, value);
      subscribers[type].forEach(notifySubscriber);
    }
  }
  
  return Object.freeze({
    subscribe,
    publish
  });
}

let eventEmitter = EventEmitter();

eventEmitter.subscribe("update", doSomething);
eventEmitter.subscribe("update", doSomethingElse);
eventEmitter.subscribe("add", doSomethingOnAdd);

eventEmitter.publish("update", {});

function doSomething(value) { }
function doSomethingElse(value) { }
function doSomethingOnAdd(value) { }