Singleton methods

In Ruby, singleton methods are methods attached to a single object rather than defined in a class. If you add a singleton method to a Ruby object, super refers to the method from the object’s class definition. jsclass allows the same behaviour. Recall our Animal class:

var Animal = new Class({
    initialize: function(name) {
        this.name = name;
    },
    speak: function(things) {
        return 'My name is ' + this.name + ' and I like ' + things;
    }
});

We can create a new animal and extend it with singleton methods. All Class-derived objects have an extend() method for doing this:

var cow = new Animal('Daisy');

cow.extend({
    speak: function(stuff) {
        return 'Mooo! ' + this.callSuper();
    },
    getName: function() {
        return this.name;
    }
});

cow.getName()   // -> "Daisy" 

cow.speak('grass')
    // -> "Mooo! My name is Daisy and I like grass"

Modules as object extensions

As well as passing simple objects into the extend() method, you can use modules. The receiving object will then gain all the methods of the module. If we extend using Observable, for example:

cow.extend(Observable);

cow.addObserver(function() {
    alert('This cow is observable!');
});

cow.notifyObservers();

This alerts "This cow is observable!", as expected. Using modules to extend objects has some interesting inheritance consequences, which are more thoroughly exposed in the inheritance article. In short, all singleton methods are stored in a module attached to the object – this is known as an eigenclass or metaclass in Ruby circles. By using a module to extend an object, the module is mixed into the eigenclass, making it part of the inheritance tree. So we can override notifyObservers(), for example, to duplicate every observer added to an object. callSuper() calls out to the module we used to extend the object.

cow.extend({
    notifyObservers: function() {
        this.callSuper();
        this.callSuper();
    }
});

// alerts "This cow is observable!" twice
cow.notifyObservers();