Classes - nodirt/defineClass GitHub Wiki

Classes

defineClass emulates classic OOP with inheritance and polymorphism.

Quick description

If you understand the following code, you don't need to read the rest.

// define a class
var Device = defineClass({
  // define a default variable name
  hasBattery: false,

  // define a constructor
  constructor: function (ram) {
    this.ram = ram;
  },

  // define a method
  turnOn: function () {
    console.log("Turning on...");
  }
});

// define a subclass
var Phone = defineClass({
  // specify the base class
  _super: Device,

  // override a constructor
  constructor: function (ram, number) {
    // you may have code before calling the base constructor
    this.number = number;
    // call the base contructor
    this._super(ram);
  },

  // override a method
  turnOn: function () {
    // call the base method
    this._super();
    console.log("Playing sound");
  },

  // define a new method
  dial: function (number) {
    console.log("Dialing to " + number);
  }
});

Got it? Then jump to Traits.

Long description

This is a step-by-step description.

Defining a class

defineClass function receives a class prototype and returns a generated a class. The special constructor method is treated as a class constructor;

var Device = defineClass({
  constructor: function (ram) {
    this.ram = ram;
  },

  turnOn: function () {
    console.log("Turning on...");
  }
});

var device = new Device(1000);
device.turnOn(); // Output: Turning on...
assert(device instanceof Device);

Default field values

If a field has an immutable default value, it can be included in the prototype.

var Device = defineClass({

  // define a default variable name
  hasBattery: false,

  constructor: function (ram) {
    this.ram = ram;
  },

  turnOn: function () {
    console.log("Turning on...");
  }
});

var device = new Device(1000);
assert(device.hasBattery === false);

Constructor is optional

Here is the minimal class definition:

var MinimalClass = defineClass({});

Inheritance

A special _super field in a prototype is reserved for inheritance and can reference a base class.

A subclass inherits the members of its base class. It is not required to re-define the constructor in a prototype.

var Phone = defineClass({

  // specify the base class
  _super: Device,

  // define a new method
  dial: function (number) {
    console.log("Dialing to " + number);
  }
});

var phone = new Phone(1000); // base constructor is called
phone.dial("120-0000"); // Output: Dialing to 120-0000
assert(phone instanceof Phone);
assert(phone instanceof Device);

Overriding methods and calling base methods

Members in a subclass override the base members of the same name. To call a base method, call the special this._super method. It applies to constructors too.

var Phone = defineClass({
  _super: Device,

  // override a constructor
  constructor: function (ram, number) {
    // you may have code before calling the base constructor
    this.number = number;
    // call the base contructor
    this._super(ram);
  },

  // override a method
  turnOn: function () {
    // call the base method
    this._super();
    console.log("Playing sound");
  },

  dial: function (number) {
    console.log("Dialing to " + number);
  }
});

var phone = new Phone(100, "120-1010");
phone.turnOn(); // Output: Turning on...\nPlaying sound
assert(phone.number === "120-1010");

The _super field value changes from method call to method call, so it may be used only in the method that has overridden the base method. Do not use it in a nested function unless you know what you are doing.

Overriding default field values

You can not only override methods but default field values as well.

var Phone = defineClass({
  _super: Device,
  hasBattery: true
});

var phone = new Phone(1000);
assert(phone.hasBattery);