Perfection Kills

by kangax

Exploring Javascript by example

Archives Posts

Semantic constructors

July 16th, 2008 by kangax

One of the easiest ways to inspect an object is to type convert it to a string:


function foo() {
  return 'foo';
}
foo + ''; // "function foo(){ return 'foo'; }"
// or
foo.toString();
// or
String(foo);

When using Class.create from prototype.js, I often get annoyed by a meaningless result of constructor’s toString:


var Person = Class.create({
  initialize: function(name) {
    this.name = name;
  },
  speak: function(msg) {
    return this.name + ' says: ' + msg;
  }
});

Person + ''; // "function klass() { this.initialize.apply(this, arguments); }"

var Employee = Class.create(Person, {
  initialize: function($super, dept) {
    $super();
    this.dept = dept;
  }
});

Employee + ''; // "function klass() { this.initialize.apply(this, arguments); }"

As you can see, constructor’s default toString tells little about what’s going on under the hood. In fact, Class.create returns a generic constructor-function which only calls initialize method of a prototype. In other words it acts as a proxy. One of the ways to see actual constructor’s code is to inspect “initialize” method directly:


// nothing new here
Person + ''; // "function klass() { this.initialize.apply(this, arguments); }"

// and the actual code
Person.prototype.initialize + ''; // "function (name) { this.name = name; }"

This is quite verbose, don’t you think? Let’s monkey patch Class.create a little:


Class.create = (function(original) {
  var fn = function() {
    var result = original.apply(null, arguments);
    result.toString = function() { return result.prototype.initialize.toString() };
    return result;
  };
  fn.toString = function(){ return original.toString() };
  return fn;
})(Class.create);

We simply redefine original Class.create with an “enhanced” version. New version “binds” toString of prototype.initialize as toString of constructor-function. As a bonus, it also takes care of a “wrapped” Class.create.toString itself – trying to be as unobtrusive as possible:


// monkey-patch Class.create first...

// Person.toString now yields much more informative result
Person + ''; // "function (name) { this.name = name; }"

// Class.create code seems to be unchanged
Class.create + ''; // outputs actual Class.create code
Filed under Class.create having 6 Comments »

« Previous Entries