Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
class inheritance for real

class inheritance the way it should have been in JavaScript.

A small sketchup of how the resulting object structure will look up: http://www.abload.de/image.php?img=inhnc45.png

Usage:

 f(p,s,i) // returns the newly created class
 p: // the parent class
 s: // a property descriptor map for the static members
 i: // a property descriptor map for the instance members

 all of p,s,i are optional.

 to create a new instance of the newly created klass do:
 klass=f(p,s,i)
 Object.create(klass.prototype) // new instance

 to check if an object is an instance of klass do
 klass.isPrototypeOf( obj)

 for more examples see the unit tests.
function(p,s,i){ // parent, static, instance in that order
s = Object.create( p||{}, s); // create the new classes static object
return(
s.prototype = Object.create( // create the new instance object
p&& p.prototype ||{}, i // attach that to the statics prototype method
)
).constructor = s // make the static the instances constructor
}
function(p,s,i){s=Object.create(p||{},s);return(s.prototype=Object.create(p&&p.prototype||{},i)).constructor=s}
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004
Copyright (C) 2011 Kambfhase
Everyone is permitted to copy and distribute verbatim or modified
copies of this license document, and changing it is allowed as long
as the name is changed.
DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. You just DO WHAT THE FUCK YOU WANT TO.
{
"name": "class inheritance",
"description": "class inheritance the way it should have been in JavaScript.",
"keywords": [
"classes",
"inheritance"
]
}
<!doctype html>
<html>
<head>
<link href="qunit.css" rel="Stylesheet" type="text/css"/>
<title>Unit Tests</title>
</head>
<body>
<h1 id="qunit-header">Din - Unit Tests</h1>
<h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2>
<ol id="qunit-tests"></ol>
<div id="qunit-fixture">test markup, will be hidden</div>
<script src="qunit.js"></script>
<script>
var Class={
create2:
function f(p,s,i){s=Object.create(p||{},s);return (s.prototype=Object.create((p&&p.prototype)||{},i)).constructor=s}
,
create: function(o){
var k = this.create2(o.parent,o.static,o.instance);
if( !k.create)
k.create = function(){return Object.create(this.prototype)};
if( !k.is)
k.is = function( obj){ return this.prototype.isPrototypeOf(obj);};
return k;
}
}
</script>
<script>
module("Basic basics");
test("Basic setup", function(){
expect(3);
ok( Class,"Class exists");
ok( Class.create,"Class.create exists");
equals( typeof Class.create, "function", "Class.create is a function");
});
module("simple class");
var Klass = Class.create({
// no parent
"static":{
method: {
value: function(){
return 2;
}
},
self: {
value: function(){
return this;
}
}
},
instance: {
method: {
value: function(){
return 2;
}
},
prop: {
value: "foo",
enumerable: true,
writable:true,
configurable:true
},
accessor: {
get: function(){
return 1;
},
enumerable: true
},
self: {
value: function(){
return this;
}
}
}
}),k=Klass.create();
test("simple basics", function(){
expect(7);
ok( Klass,"Klass exists");
ok( Klass.prototype,"Klass.prototype exists");
ok( Klass.prototype.constructor== Klass, "Klass is its instances Constructor");
equals( typeof Klass.create, "function", "Klass.create is a function");
equals( typeof Klass.is, "function", "Klass.is is a function");
ok( Klass.create(), "Klass.create returns something");
//ok( k instanceof Klass, "k is an instance of Klass"); //?
ok( Klass.is( k),"k is an instance of Klass");
});
test("correct instances",function(){
expect(7);
equals( typeof k.method, "function","k.method should be a function");
equals( k.method(), 2, "yay!");
equals( typeof k.prop, "string","k.prop is a string");
equals( k.prop, "foo");
equals( typeof k.accessor, "number","getter returns a value");
equals( k.accessor, 1,"accessor returns gettet value");
ok( k.self() == k,"correct <this>");
});
test("correct descriptors",function(){
var p = Klass.prototype, d;
expect(13);
ok( p.hasOwnProperty("method"),"method should be on the prototype");
d=Object.getOwnPropertyDescriptor(p, "method");
equals(d.enumerable, false, "method is not enumerable");
equals(d.writable, false, "method is not writable");
equals(d.configurable, false, "method is not configurable");
ok( p.hasOwnProperty("prop"),"prop should be on the prototype");
d=Object.getOwnPropertyDescriptor(p, "prop");
equals(d.value, "foo", "prop is 'foo'");
equals(d.enumerable, true, "prop is enumerable");
equals(d.writable, true, "prop is writable");
equals(d.configurable, true, "prop is configurable");
ok( p.hasOwnProperty("accessor"),"accessor should be on the prototype");
d=Object.getOwnPropertyDescriptor(p, "accessor");
ok(d.get, "getter is defined");
equals(d.enumerable, true, "accessor is enumerable");
equals(d.configurable, false, "accessor is not configurable");
});
test("Staticness",function(){
expect(4);
ok( Klass.method, "static method exists");
ok( Klass.method != k.method, "static and instance method differ");
equals( Klass.method(), 2, "static returns correct result");
ok( Klass.self() == Klass, "correct <this>");
});
module("inheritance");
var A = Class.create({
instance : {
foo: {
value: function(){
return "A foo";
}
}
}
}),
B = Class.create({
parent: A,
"static":{
bar: {
value: function(){
return "b bar";
}
}
}
}),
C = Class.create({
parent: B,
instance: {
foo: {
value: function(){
return "C "+A.prototype.foo.call(this);
}
}
}
}),a=A.create(),b=B.create(),c=C.create();
test("static inheritance", function(){
expect(4);
ok( !!B.bar(),"B has a static bar method");
ok( !!C.bar(),"C has a static bar method");
equals( B.bar, C.bar,"C inherits static method from B!");
equals( B.bar(), C.bar(), "same!");
});
test("creation", function(){
expect(9);
equals( A.is( a), true, "a is an instance of A");
equals( A.is( b), true, "b is an instance of A");
equals( A.is( c), true, "c is an instance of A");
equals( B.is( a), false, "a is not an instance of B");
equals( B.is( b), true, "b is an instance of B");
equals( B.is( c), true, "c is an instance of B");
equals( C.is( a), false, "a is not an instance of C");
equals( C.is( b), false, "b is not an instance of C");
equals( C.is( c), true, "c is an instance of C");
});
test("instance inheritance",function(){
expect(4);
equals( a.foo(), "A foo", "a foo is a foo :|");
equals( b.foo(), "A foo", "b.foo is also a foo :|");
equals( b.foo, a.foo, "same foo methods");
equals( c.foo(), "C A foo","c foo is c a foo");
});
</script>
</body>
</html>
@atesgoral

This comment has been minimized.

Copy link

commented Jul 13, 2011

You could probably alias Object.create and prototype to shave off some bytes.

@Kambfhase

This comment has been minimized.

Copy link
Owner Author

commented Jul 13, 2011

oh, yeah, will do!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.