Create a gist now

Instantly share code, notes, and snippets.

@jdalton /def.js Secret forked from tobytailor/def.js
Created Jul 14, 2010

What would you like to do?
* def.js: Simple Ruby-style inheritance for JavaScript
* Copyright (c) 2010 Tobias Schneider
* This script is freely distributable under the terms of the MIT license.
(function(global) {
// used to defer setup of superclass and plugins
var deferred;
function addPlugins(plugins) {
augment(this.prototype, plugins);
return this;
// TODO: Ensure we fix IE to iterate over shadowed properties
// of those further down the prototype chain. There is also a
// bug in Safari 2 that will match the shadowed property and
// the one further down the prototype chain.
function augment(destination, source) {
for (var key in source) {
destination[key] = source[key];
// dummy subclass
function Subclass() { }
function def(klassName, context) {
// create class on given context (defaults to global object)
var Klass =
(context || global)[klassName] = function Klass() {
// called as a constructor
if (this != global) {
// allow the init method to return a different class/object
return this.init && this.init.apply(this, arguments);
// called as a method
// defer setup of superclass and plugins
deferred._super = Klass;
deferred._plugins = arguments[0] || { };
// add static helper method
Klass.addPlugins = addPlugins;
// called as function when not
// inheriting from a superclass
deferred = function(plugins) {
return Klass.addPlugins(plugins);
// valueOf is called to setup
// inheritance from a superclass
deferred.valueOf = function() {
var Superclass = deferred._super;
if (Superclass) {
Subclass.prototype = Superclass.prototype;
Klass.prototype = new Subclass;
return Klass.addPlugins(deferred._plugins);
return deferred;
// expose
global.def = def;
// Example
def ('Person') ({
'init': function(name) { = name;
'speak': function(text) {
alert(text || 'Hi, my name is ' +;
def ('Ninja') << Person ({
'kick': function() {
this.speak('I kick u!');
var ninjy = new Ninja('JDD');

indutny commented Jul 14, 2010

May be add "super" attribute in constructor function?


jdalton commented Jul 14, 2010

@donnerjack13589 Sure thing, a lot can be done still.

indutny commented Jul 14, 2010

Also, may be add plugins not only to prototype but to constructor too?


jdalton commented Jul 14, 2010

True. Ya, I don't know how far I want to take this.

I do a lot of this in FuseJS already.

I forked Tobias' gist primarily to clean it up and add comments explaining the coolness ;D

indutny commented Jul 14, 2010

Clean up? Are you joking?
You've rewrited most of it. Only idea has survived

That's a very interesting approach @jdalton...

upz, congratulations to both @tobeytailor and @jdalton

This is really neat.

Two questions though:

How does the << syntax work?

Isn't superclass supposed to be a property of the instances you create? It's not coming through. If it's not meant to be there, how does method overloading work?


jdalton commented Jul 14, 2010


  1. I added a comment to the usage example explaining your first question.

  2. The superclass property is not on the subclass instance but on the subclass constructor.

    Method overloading and a magic super method isn't supported in this gist.

Regardless of the magic aspect, there is no way to do:
this.constructor.superclass.speak("super text");
from within Ninja's speak method, correct?

I just want to make sure I'm not doing something wrong :)

indutny commented Jul 14, 2010

Look at this:

Sorry for comments on russian. But in this fork you can use your code.

May be add plugins not only to prototype?


git remote add donnerjack13589 git://
git pull donnerjack13589 master --commentignore=russian

If only :). Thanks for the info!


jdalton commented Jul 14, 2010

Tobias has set up a github repository for this now :D

indutny commented Jul 14, 2010

Yep, will look tomorrow. But I don't like his super feature (it makes code bigger)

indutny commented Jul 15, 2010

I've added my fixes here, also I've added multiple inheritance.
def ('a') << b()
def ('a') << c()

Also attributes/methods of superclass(and other parent classes) can be accessed from child.
def ('b') ({a:1})
def ('a') << b()
a.a === 1


jdalton commented Jul 15, 2010


I don't see any real inheritance being set up.
You are just porting methods from one object two another in a loop

indutny commented Jul 15, 2010


Real inheritance can be set up only for _super class, cause js doesn't support real multiple inhertance.
But this methods will be in every object, created from this class.

And also you can do following:
def ('a') ({a : 1})
def ('a') ({b : 1})


jdalton commented Jul 15, 2010

Ok. So it's more like single inheritance + mixins

indutny commented Jul 15, 2010


There is some prob in IE with

if (this != context)

as I mentioned on Twitter, it doesn't work in IE, so I replaced it with this.constructor == Klass as a quick fix. However, I found out that

if (context != this)

already works fine ;) Yet another crazy IE thing. Try to attach via debugger to IE (via standard Developer Tools of IE8, put breakpoint there, and you'll see this value confusion). So, I've changed this.constructor == Klass to if (context != this).

Also, I first used one < (as Ruby has), but not <<, but then found out that Chrome can't handle it, so I backed it to <<.



jdalton commented Jul 16, 2010

Right, the global object is notorious for it's weird matching in JScript:
alert(window == document); // true;
alert(document == window); // false

This is why I avoid that gotcha here;

I should have guessed it would carry over to this

alert((function(x){ return x})(this) == window); // true
alert((function(x){ { return this == x }; return })(this)); // false
alert((function(x){ { return x == this }; return })(this)); // true

Yeah, I knew about window == document (and vice-versa) issue in IE, but the second case was not so easy to catch at first glance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment