Classless OOP in JavaScript

Cristian Salcescu
Frontend Weekly
Published in
3 min readJan 12, 2018

The simplest yet elegant way of creating objects in JavaScript is using the object literal. However it has the limitation of making all its members public and often this is losing context (like in nested functions).

Trying to make the object creation familiar to Java developers, JavaScript initially introduced the Constructor Function. All members of objects created using the Constructor Function are public and these objects are fragile as this is not referring to the current object in many cases :

Also the API of these objects is mutable, so the API can be modified from outside the object.

When trying to use the Constructor Function for inheritance the syntax becomes ugly. The new class syntax offers a much cleaner code but has the same limitations as the Constructor Function:

The Classless OOP paradigm offers a much better way of creating objects by combining closures with an object literal. In this paradigm there will be two kind of objects:

  • OOP Objects
  • Data Objects

OOP Objects are about:

  • Methods. All data will be private, these objects will expose only methods
  • Immutable API
  • No more “this” loosing context problems

Objects are not data structures. Objects may use data structures; but the manner in which those data structures are used or contained is hidden…Therefore Objects are about functions not about state.

Objects are bags of functions, not bags of data.

Robert Martin

OOP Objects are build using Factory Functions (aka Power Constructor). By removing the self executing part from the Reveling Module Pattern you get a Factory Function.

function Timer(){    
return Object.freeze({
});
}

As an example I’m using the Timer Factory Function to build an OOP object. The internal data of the timer it’s private and I can only interact with it using the public API : start() and stop().

function Timer(fn, interval){
“use strict”;
var timerId;
function startRecursiveTimer(){ /*code*/ }
function stop(){ /*code*/ }
function start(){ /*code*/ }

return Object.freeze({
start : start,
stop : stop
});
}
function print() { /*code*/ }
var timer = Timer(print, 2000);
timer.start();

The memory cost of the Factory Function can be noticed when creating thousands of the same object, but this is not the case as we usually build one or a few instances of OOP Objects per Factory Function.

The memory cost (in Chrome)
+-----------+------------+------------+
| Instances | 10 methods | 20 methods |
+-----------+---------------+---------+
| 10 | 0 | 0 |
| 100 | 0.1Mb | 0.1Mb |
| 1000 | 0.7Mb | 1.4Mb |
| 10000 | 7.3Mb | 14.2Mb |
+-----------+------------+------------+

Data Objects (aka Data Structures):

  • Contain only public data
  • Are used as input/output from OOP Objects’ methods
  • Can be created using an object literal or Object.create()

--

--