JavaScript Classes

From Exterior Memory
Jump to: navigation, search

Javascript 1 (Ecma-262, editions 3 or 5) is an object-oriented language that does not support classes. Instead, Javascript is prototype based, which gives many of the benefits that classes also have, like objects and code-reuse. The distinction between a class and a prototype, is that a class behaves like a type, whereas a prototype behaves like a blueprint which you can instantiate and extend. (More experienced programmers may see an analogy here in the distinction between strict typed languages such as Java and dynamic typed languages such as Python and Ruby.)

Stoyan Stefanov wrote an excellent article: 3 ways to define a JavaScript class. Douglas Crockford (author of JavaScript)'s Private Members in JavaScript is also worth a read.

Objects and Arrays

Two ways to create an object:

var o = {};

var o = new Object();

Two ways to create an array:

var a = [];

var a = new Array();

If you leave out the var keyword in the above examples, you will be doing an assignment:

o = {};
a = [];

However, in default (non-strict) JavaScript, the variable will be created if it hadn't been defined before. It is recommended to always use the var keyword to prevent accidental assignments, and to prevent waste of time looking through the scope table.

Namespace

Create a namespace:

MyLibrary = {}
MyLibrary.Object1 = ...
MyLibrary.Object2 = ...

Function

Two ways to create a Function:

function myadd1(first, second) {
  return first + second;
}
var myadd2 = function (first, second) {
  return first + second;
}

To call a function:

myadd1(1, 2);
myadd2(1, 2);

Scope

To create a scope (for local variables) use an anonymous function and immediately call this function (it's a hack, but it works):

( function() {
    // local variable
    var myvar = 3;
    
    // ....
}());

Classes

To create a prototype (create a class), use a function:

// constructor function
function MyClass () {
  this.variable = 0;
}

To add methods to the class, use the prototype property:

MyClass.prototype.setVariable = function (value) {
  this.variable = value;
};

MyClass.prototype.getVariable = function () {
  return this.variable;
};

An alternative, which is somewhat more readable is:

// constructor function
MyClass = function () {
  this.variable = 0;
}

// methods
MyClass.prototype = {
  setVariable: function (value) {
    this.variable = value;
  },
  getVariable: function () {
    return this.variable;
  }
}

Note that the following code gives the same result, but consumes more memory, since the methods would be recreated each time the class is instantiated. We'll see these again later (these are actually privileged methods)

// constructor function
function MyClass () {
  this.variable = 0;
  
  this.setVariable = function (value) {
    this.variable = value;
  };
  
  this.getVariable = function () {
    return this.variable;
  };
}

Extending Classes

Javascript does not have a concept of subclasses and superclasses, but objects (including classes) can be extended. Instead, classes can be extended by copying methods from one class to another class.

Given this base class:

function MyClass () {
  this.variable = 0;
}
MyClass.prototype.setVariable = function (value) {
  this.variable = value;
};
MyClass.prototype.getVariable = function () {
  return this.variable;
};

It is possible to create another class that inherits the selected methods:

function MySubclass () {
  this.variable = 0;
}
MySubclass.prototype.setVariable = MyClass.prototype.setVariable;
MySubclass.prototype.getVariable = MyClass.prototype.getVariable;

Class Instances

To instantiate a prototype (create an object):

// new object instance
var myObj = new MyClass();

myObj.setVariable(8);
alert(myObj.getVariable());

In the above example, variable is publicly accessible, so you can directly access it:

myObj.variable = 8;
alert(myObj.variable);

Static Methods

The static method is just a regular function. It uses the MyClass namespace, but has no relation with any MyClass object instance.

To create a static method (observe the difference with MyClass.prototype.method):

MyClass.staticMethod = function () {
    // ...
};

To call a static method:

MyClass.staticMethod();

Private and Privileged Methods

Variables declared within scope of a function are private, and can only be accessed from other private functions:

// constructor function
function MyClass () {
  var privateVariable; // private member only available within the constructor.
  
  var initData = function () {
    // ..
  };
};

The variable privateVariable and method initData() are both private: they can not be accessed from public methods. That makes them less useful.

A privileged method is a method that can be accessed by public methods and the outside, and can also access private variables.

// constructor function
function MyClass () {
  var variable = 0; // private variable
  this.setVariable = function (value) {
    variable = value;
  };
  
  this.getVariable = function () {
    return variable;
  };
}

setVariable() and getVariable() can be accessed from the outside, and manipulate the private variable. The disadvantage of protected methods (and of private methods) is that they are redefined every time the constructor function is called (thus they are redefined for every instance). This may take a bit of memory.

Some authors opt to make all variables and methods public, but use an underscore for low level methods that generally should not be accessed from outside.


// constructor function
MyClass = function () {
  this._variable = 0;
}

// methods
MyClass.prototype = {
  setVariable: function (value) {
    this._variable = value;
  },
  getVariable: function () {
    return this._variable;
  }
}

Design Pattern

A small overview of the different variables and methods.

// constructor function
function MyClass () {
  this.publicVariable; // can be accessed within constructor and from the outside
  var privateVariable; // can be accessed within constructor but not from the outside
  
  var privateMethod = function () {
    // it can access private members, and can not be accessed outside the constructor
    //..
  };
  this.privilegedMethod = function () {
    // it can access private members, and can be accessed outside the constructor
    //..
  };
};
MyClass.prototype.publicMethod = function () {
  // it can not access private members, and can be accessed outside the constructor
  //..
};