I started writing a class implementation for my JavaScript framework, which I’m using on my sites as a lightweight toolkit when I don’t need something heavyweight like MooTools or jQuery. I decided to write a class implementation mainly to make inheritance easier. This was heavily inspired by the [url=http://mootools.net/docs/core/Class/Class]Class system in MooTools, [url=http://ejohn.org/blog/simple-javascript-inheritance/]John Resig’s Simple JavaScript Inheritence, [url=http://dean.edwards.name/weblog/2006/03/base/]Dean Edwards’ Base.js and [url=http://myjs.fr/my-class/]My.js. I’d like someone experienced to go over the code and let me know if it has any issues.
Here’s the code so far:
/**
* Daniel15 JavaScript Framework - By Daniel15, 2012
* http://dl.vc/jsframework
* Feel free to use any of this, but please link back to my site (dan.cx)
*/
(function()
{
/**
* Create a new class instance
* @param Object Functions to add to the class
* @param Class Class to extend, if any
* @return Class instance
*/
var Class = window.Class = function(proto, extendThis)
{
// Create the class constructor
//var NewClass = proto.init ? proto.init : function() {};
function NewClass()
{
if (this.init)
this.init.apply(this, arguments);
}
NewClass.extend = Class.extend;
// If not extending, easy - Just assign the prototype directly
if (!extendThis)
{
NewClass.prototype = proto;
return NewClass;
}
// Extending - Create an instance of the parent class to use as the prototype
// But *don't* run the constructor (creates an empty constructor first)
function ParentClassEmpty() {}
ParentClassEmpty.prototype = extendThis.prototype;
NewClass.prototype = new ParentClassEmpty;
// Add all the new methods to the prototype
for (var name in proto)
{
if (!proto.hasOwnProperty(name))
return;
// Does this function already exist on the parent class?
if (extendThis.prototype[name])
NewClass.prototype[name] = Class.wrapFn(extendThis.prototype[name], proto[name]);
else
// No parent method with the same name, so we can just copy it directly
NewClass.prototype[name] = proto[name];
}
return NewClass;
};
// Add useful functions to the Class object
Util.extend(Class,
{
/**
* Extend the current class. Expected to be called in the context of an existing class.
* @param Object Prototype methods of new class
* @return Class instance
*/
extend: function(proto)
{
return new Class(proto, this);
},
/**
* Create a wrapper for this function. This wrapper saves the parent function into .parent
* (so it can be called from the overriding function) before calling the overriden function.
* @param Function Function on the superclass
* @param Function Function on the overriding class
* @return Function
*/
wrapFn: function(superFn, fn)
{
return function()
{
// Save the current parent method
var tmp = this.parent;
this.parent = superFn;
var ret = fn.apply(this, arguments);
// Restore whatever was in .parent before
this.parent = tmp;
return ret;
};
}
});
})();
And here’s an example usage:
var Person = new Class(
{
init: function(name)
{
//console.log('Init person');
this.name = name;
},
helloWorld: function()
{
return 'Hello';
},
helloWorld2: function()
{
return 'Hello2';
}
});
var me = new Person('Daniel');
console.log('me.name = ', me.name); // Daniel
console.log('me.helloWorld() = ', me.helloWorld()); // Hello
console.log('me.helloWorld2() = ', me.helloWorld2()); // Hello2
console.log('me instanceof Person = ', me instanceof Person); // true
var Ninja = Person.extend(
{
helloWorld2: function()
{
return 'Ninja helloWorld2, original = ' + this.parent();
},
helloWorld3: function()
{
return 'Ninja helloWorld3';
}
});
var awesome2 = new Ninja('Awesome');
console.log('awesome2.name = ', awesome2.name); // Awesome
console.log('awesome2.helloWorld() = ', awesome2.helloWorld()); // Hello
console.log('awesome2.helloWorld2() = ', awesome2.helloWorld2()); // Ninja helloWorld2, original = Hello2
console.log('awesome2.helloWorld3() = ', awesome2.helloWorld3()); // Ninja helloWorld3
console.log('awesome2 instanceof Ninja = ', awesome2 instanceof Ninja); // true
console.log('awesome2 instanceof Person = ', awesome2 instanceof Person); // true
Util.extend is simply:
/**
* Add all elements from source to destination and return the modified destination (for chaining)
* @param Object to copy properties to
* @param Object to copy properties from
*/
extend: function(destination, source)
{
for (var key in source || {})
{
if (source.hasOwnProperty(key))
destination[key] = source[key];
}
return destination;
},
Thoughts?