Object oriented programming in Javascript
this is an adaption of the original article
Object oriented programming in Javascript.
A minimalist approach
Published: 2012-03-01
There are many ways to use object oriented techniques in JavaScript. Still, a lot of people think JavaScript is not an object oriented language because it does not have the concept of a class. In my opinion, the fact that JS does not have a class statement makes JS even more object oriented. While class based languages like Java focus on objects indirectly (you never write objects, you always write classes), JS focuses on objects directly. In JavaScript you deal with real objects instead of classes. Here I present my favourite, minimalist way to work with objects in JavaScript.
Literals
The minimalist approach to write object oriented code in Javascript centers around the concept of literals. Literal objects are created like this:
car = {};
Constructors
Because we have no classes in Javascript, the minimalist approach to do OOP in Javascript is to use objects that play the role of classes. We call these objectsbuilders. Builders produce build objects. Builders are nothing more than object factories; objects that produce other objects.
Cat = {
createNew: function(){
var cat = { 'name':'Sylvester' };
return cat;
}
}
This object named 'Cat' acts as a class and contains a factory method called 'createNew' that works like a constructor. The builder assembles an object called 'cat' and returns a reference to this newly created instance.
The 'cat' instance returned by 'createNew' looks like:
{ 'name' : 'Sylvester' }
If we ask the cat to print its name; it will print 'Sylvester':
alert( cat.name ); //will print 'Sylvester'
Methods
Let's see how we can add a method to an object in a builder and then invoke that method from outside the builder:
Cat = {
createNew: function() {
var cat = {}; //create an empty build object
cat.makeSound= function(){ //add logic
alert('meow');
}
return cat; //return the fabricate
}
}
var cat = Cat.createNew();
cat.makeSound(); //prints meow
The 'createNew' method is an example of a static method, to mimic static methods simply add functions to the builder object instead of the object that is being built.
Note that we did not use the this-keyword. We don't need it. An instance method may call another instance method by simply referring to the build object:
Cat = {
createNew: function() {
var cat = {}; //create an empty object
cat.makeSound = function(){ //add logic
alert('meow');
}
cat.makeSoundIndirectly = function() {
cat.makeSound(); //use cat instead of this
}
return cat; //return the fabricate
}
}
var cat = Cat.createNew();
cat.makeSoundIndirectly(); //prints meow
Private properties
Making properties private is easy, because JavaScript has lexical scoping. This means that if you declare a variable or function within a certain lexical scope, only functions in that same block of code will be able to access it. This may sound a little abstract, so here is an example:
Cat = {
createNew: function() {
var cat = {};
var sound = 'meow'; //sound is local
cat.makeSound = function(){
//can reach sound from here
alert( sound );
}
return cat;
}
}
var cat = Cat.createNew();
cat.makeSound();
//but can't reach sound from here
alert(cat.sound); //fail!
The variable 'sound' acts a private property of 'cat'. In contrast to what most people believe about JavaScript it is perfectly possible to create a truly private property like this (actually you can still access it using eval("sound='whaf!'",Cat.createnew); however it's private 'enough' for practical usage, remember that other languages offer reflection techniques to change private properties). The variable 'sound' will not be accessible from outside the 'createNew' function. If you invoke 'makeSound', the property becomes accessible again because 'makeSound' shares the same lexical scope as 'sound'. This way, you mimic the behaviour of a private property.
Inheritance
Instead of creating a brand new 'Cat' object we use the 'Animal' object as our base type, then we add our 'Cat' specific modifications and we are done:
Animal = {
createNew: function() {
var animal = {};
animal.eat = function(){ alert('eating'); }
return animal;
}
}
Cat = {
createNew: function() {
var cat = Animal.createNew(); //Inherits
var sound = 'meow';
cat.makeSound= function(){
alert( sound );
}
return cat;
}
}
var cat = Cat.createNew();
cat.makeSound();
cat.eat();
In fact, inheritance in JavaScript is more like 'we turn an Animal into a Cat'.
Protected Properties
Although a protected property is inaccessible from the outside, all objects that are part of the same family tree may share the protected components. To implement protected properties we create a new object called 'protect' that contains the shared stuff. I like to call this shared object, a bundle. If a bundle is passed to the 'Animal' constructor, the constructor will add new items to the bundle, if not it simply creates a new bundle. If the 'Cat' wishes to make use of the protected bundle, it simply passes the shared object to 'Animal':
Animal = {
createNew: function( bundle ) {
var animal = {};
var protect = bundle || {};
protect.sound = 'growl';
protect.makeSound = function(){
alert( protect.sound );
}
return animal;
}
}
Cat = {
createNew: function() {
var protect = {};
var cat = Animal.createNew( protect );
protect.sound = 'meow!';
cat.meow = function(){ protect.makeSound(); };
return cat;
}
}
var cat = Cat.createNew();
cat.meow();
Now, with these tools you can build object oriented designs. You can useencapsulation, inheritance and composition. Design patterns like singletons, factories and visitors are also easy to implement this way. Note that we did not use a lot of confusing JS stuff: no this, no new, no prototype. Therefore this approach is not only easy, minimalist and elegant but it also works in the most ancient and exotic browsers.
back to homepage

浙公网安备 33010602011771号