Implementing public, private, and static data members in pre-ES5 Javascript
December 09, 2019
Today many of you might be saying Javascript is not a very object-oriented programming language and that it lacks the ability of data hiding. But for a language as evolving as Javascript, there are always new features being introduced.
The classes came to Javascript with the introduction of ECMAScript 2015. It doesn’t introduce any new OOP inheritance model in Javascript but was a plain syntax sugar over already existing prototypal inheritance. Even a bunch of new features around classes are in the pipeline (as at the time of writing this post), including class field declarations and private fields, which are at stage 3 under the class-fields proposal.
Again, that will only introduce just a new syntax sugar in the language. In this post, we will learn how the classes
actually, work under the hood and how we can implement public
, private
, and static
properties and
methods in Javascript.
ES5 Classes
Let us take a look at the ES5 classes. Nothing special but just plane class format as in most of the languages.
class foo {
constructor(bar){
this.bar = bar;
}
//
print() {
console.log(this.bar);
}
//
}
//
const baz = new foo('bar');
baz.print();
Let us see how we could have implemented this same class before es5 came and learn how the classes work under the hood.
So in the below code, you will see the implementation of the same foo
class from above using a function.
function foo (bar) {
// constructor code starts
this.bar = bar;
// constructor code ends
//
this.print = function () {
console.log(this.bar);
};
}
//
const baz = new foo('bar');
baz.print();
Try running both of these code snippets above and you’ll get the same output. This is how you can achieve writing a a class implementation supporting old browsers, without using es5 classes.
The functional implementation of a class in Javascript is actually more powerful than using es5 classes. ES5 classes
provides nothing like private
or static
.
Let’s see how we can implement all these class features that are necessary for an object-oriented architecture, in Javascript.
Public
The data members or member functions of an object are all public. Any other part of the code can modify or delete them. There are two ways to add public data member and member function in an object. The first way is to create it in the constructor function.
function foo() {
// inside constructor function
this.bar = 'initial data';
}
//
// create a new object using foo as constructor
const baz = new foo();
// bar is a public data member of baz object
console.log(baz.bar);
//
// we can change the value of baz.bar
baz.bar = 'changed data';
console.log(baz.bar);
Creating a public
data member is as easy as that. We use this method of creating public data members through inside
the constructor functions most of the time to initialize data for the new object. The second way to create public data
members is to attach it to the constructor’s prototype. This is used to add member functions for inheritance while conserving
memory. Any property which is not available at the object is checked in the prototype chain.
// constructor function
function foo(bar) {
this.bar = bar;
}
// adding a method to constructor function's prototype
foo.prototype.print = function() {
console.log(this.bar);
}
//
const baz = new foo('bar');
baz.print();
Private
Well, this is something new we have to learn. ES5 classes do not provide the functionality of private
data members or
member functions. Data abstraction is a key phenomenon of object-oriented programming. But it is not something
you cannot do with Javascript. Let us learn how we can achieve data abstraction with creating private
data members.
// constructor function
function tesla() {
// private data member
let battery = 100;
//
// privileged member function
this.drive = function(kms) {
battery -= Math.min(battery, kms/10);
};
//
// privileged member function
this.charge = function(hours) {
battery += Math.min(100 - battery, 20 * hours);
};
//
// privileged member function
this.range = function() {
console.log('Car can run for '+ battery * 10 + ' kms');
};
};
//
const car = new tesla();
// will give undefined
console.log(car.battery);
//
/* drive, charge, and range have access
* to the battery and can modify it. */
car.range();
car.drive(1000);
car.range();
//
car.charge(2);
car.range();
Any variable declared inside the constructor functions, also including the constructor’s params are private to the scope
of the constructor function. In the above code snippet, battery
is the private data member of car
object. drive
,
charge
, and range
are privileged member functions, they have access to the private battery
property and can change
it. But you cannot do that from outside of the car
object.
Try tweaking the code, maybe making your car more efficient, well I am happy with the 1000kms range.
:smile:
Static
Now let’s learn how we can implement static
data members in functional classes. The static
data members belong to the
constructor function rather than the objects. Let us build a simple object counter.
const foo = function() {
function foo() {
foo.count++;
this.roll = foo.count;
};
//
foo.count = 0;
return foo;
}();
//
const bar = new foo();
const baz = new foo();
//
console.log(bar.roll, baz.roll);
Though not with es5 you can implement static data members using the class syntax in es6. In this post, we learned how
we can implement public
, private
, and static
data members in Javascript using functional classes.
You can ask your questions or submit feedback in the comments. Also do not forget to try the functional inline code editor and compiler in this post.