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();