Monday, January 10, 2011

Pretending Javascript has Object Orientation

Suppose I have a Prototype.js class:

var Parent = Class.create({
initialize: function() {... }
invariantProcess: function() {
part1: Prototype.emptyFunction,
part2: Prototype.emptyFunction,

and a subclass

var Child = Class.create(Parent,{
initialize: function($super) { $super... }
part1: function() { ... draw part 1 ... },
part2: function() { ... draw part 2 ... },

Ordinarily, inheritance and virtual dispatching allows us to override part1 and part2 without touching the invariantProcess in the base class. This often fails in Javascript as an indirect side-effect of the fact that classes are library constructs, not first-class objects.

In Javascript, what is commonly called "inheritance" is actually just copying properties around instances and instance prototypes, and names in method bodies are lexically bound to the scope in which the method is defined.

None of that is a bad thing. The bad thing is when you take a second-class method and treat it as if it were an independent function. This can happen, for instance, when you pass the method as a callback function. The bindings can get botched, with names either undefined or bound to the wrong object. In the example above, "this" might not be the "this" that we want it to be.

I ran across this recently while creating Prototype.js class wrappers for a Processing.js example. Processing expects a callback that will bind a drawing function to the library, but when a method is used as the callback it can horribly ugly to get the bindings correct.

The solution generally amounts to using a Factory pattern, returning a new function with the critical variables defined in the enclosing scope. This all but rules out using methods directly, which then take the role as supporting functions instead.

No comments: