dean.edwards.name/weblog/2006/03/base/

A Base Class for JavaScript Inheritance

NB. I’ve amended the code samples below to reflect recent changes in this class.

I’m an OO programmer at heart and JavaScript supports prototype based inheritance. Unfortunatley this leads to verbose class definitions:

function Animal(name) {};
Animal.prototype.eat = function() {};
Animal.prototype.say = function(message) {};

I want a nice base class for JavaScript OO:

The Base Class

I’ve created a JavaScript class (Base.js) that I hope eases the pain of JavaScript OO. It’s a simple class and extends the Object object by adding two instance methods and one class method.

The Base class defines two instance methods:

extend

Call this method to extend an object with another interface:

var object = new Base;
object.extend({
	value: "some data",
	method: function() {
		alert("Hello World!");
	}
});
object.method();
// ==> Hello World!
base

If a method has been overridden then the base method provides access to the overridden method:

var object = new Base;
object.method = function() {
	alert("Hello World!");
};
object.extend({
	method: function() {
		// call the "super" method
		this.base();
		// add some code
		alert("Hello again!");
	}
});
object.method();
// ==> Hello World!
// ==> Hello again!

You can also call the base method from within a constructor function.

Creating Classes

Classes are created by calling the extend method on the Base class:

var Animal = Base.extend({
	constructor: function(name) {
		this.name = name;
	},
	
	name: "",
	
	eat: function() {
		this.say("Yum!");
	},
	
	say: function(message) {
		alert(this.name + ": " + message);
	}
});

All classes created in this manner will inherit the extend method so we can easily subclass the Animal class:

var Cat = Animal.extend({
	eat: function(food) {
		if (food instanceof Mouse) this.base();
		else this.say("Yuk! I only eat mice.");
	}
});
	
var Mouse = Animal.extend();

Class Properties and Methods

A second parameter passed to the extend method of a class defines the class interface:

var Circle = Shape.extend({ // instance interface
	constructor: function(x, y, radius) {
		this.base(x, y);
		this.radius = radius;
	},
	
	radius: 0,
	
	getCircumference: function() {
		return 2 * Circle.PI * this.radius;
	}
}, { // class interface
	PI: 3.14
});

Note the use of the base method in the constructor. This ensures that the Shape constructor is also called. Some other things to note:

Classes With Private Data

Some developers prefer to create classes where methods access private data:

function Circle(radius) {
	this.getCircumference = function() {
		return 2 * Math.PI * radius;
	};
};

You can achieve the same result using the Base class:

var Circle = Shape.extend({
	constructor: function(radius) {
		this.extend({
			getCircumference: function() {
				return 2 * Math.PI * radius;
			}
		});
	}
});

The code is slightly more verbose in this case but you get access to the base method which I find incredibly useful.

Single Instances

I changed my mind a lot about this but finally decided to allow the creation of single instance classes by defining a null constructor:

var Math = Base.extend({
	constructor: null,
	PI: 3.14,
	sqr: function(number) {
		return number * number;
	}
});

Conclusion

This supersedes my old OO framework which was not as cross-browser as I would have liked (and had other shortcomings).

I have a development area where I’m developing bits and pieces based on this engine. Most of this is work in progress but illustrates the flexibility of this technique.

You can grab the Base class here: Base.js.

Update. I’ve posted a follow-up to this post with some improvements suggested in the comments below.

Comments (218)

Leave a comment

Comment: #1

In the Circle examples you have declared a method “area” which is “perimeter” instead spacer Area is Math.PI *this.radius ^ 2

Anyway it’s really a simple and effective system to simplify class declaration and inheritance.

  • Comment by: Franco Ponticelli
  • Posted:

Comment: #2

The JS inheritance class that I use is from Doug Crockford. It’s a nice simple class inheritance base class that just modifies the main Function class. It supports calling parent methods and doing multiple inheritence (which thus far I have never found a need for)

The only change I had to make from his code to make it fully cross-browser (opera had some issues) was to change his declaration of ‘uber’ in the ‘inherits’ method to NOT specify “function uber(name)” but instead use “function (name)” (anonymous function).

  • Comment by: Edward Rudd
  • Posted:

Comment: #3

@Franco – Oops! Fixed now. Thanks. Maths was never my strong point (actually it was but I’ve now forgotten everything spacer )

  • Comment by: -dean
  • Posted:

Comment: #4

What benefits do you think this has over the Object.extend() and Class.create() features of Prototype?

  • Comment by: Jonathan Snook
  • Posted:

Comment: #5

not work in firefox

“prototype.call is not a function”

  • Comment by: modi
  • Posted:

Comment: #6

@modi – What doesn’t work?

  • Comment by: -dean
  • Posted:

Comment: #7

I got message “prototype.call is not a function” in Javascript Console when i try to Creating Class

  • Comment by: modi
  • Posted:

Comment: #8

@modi – you are going to have to show me some code. I’ve created dozens of classes in Firefox and have not seen the error you mention.

  • Comment by: -dean
  • Posted:

Comment: #9

I was also about to ask the same thing as Jonathan…

  • Comment by: Mislav
  • Posted:

Comment: #10

@Mislav/Jonathon,

There is nothing wrong with Prototype’s method. I prefer mine for the following reasons:

  1. the inherit method
  2. readability

It’s like comparing x=x+1 with x++. A slight improvement but an improvement nonetheless.

Read this for a better explanation: www.sitepoint.com/blogs/2006/01/17/javascript-inheritance/.

  • Comment by: -dean
  • Posted:

Comment: #11

As for readability, I see hardly a difference. As for the inherit method, this is really a blank spot in prototype.js

Unless you apply the patch from dev.rubyonrails.org/ticket/4060

  • Comment by: Martin Bialasinski
  • Posted:

Comment: #12

@Martin – This is not designed to compete with Prototype. If people are comfortable with that library then they should continue using it. I wrote this for my own needs and I thought I’d share it.

  • Comment by: -dean
  • Posted:

Comment: #13

Dean, I think when you’re writing “overload”, you mean “override”.

Two method declarations of the same name but different parameter lists are said to be “overloaded”. This isn’t possible in JS (unless you count using the arguments object and inspecting the passed argument types).

A method reimplemented which was defined in a superclass is said to be “overridden”.

Right?

  • Comment by: Jeremy Dunck
  • Posted:

Comment: #14

Ah, that really makes a difference. I particulary like Ben’s patch; thanks for the link, Martin.

Dean: about singletons… The example provided isn’t exactly a singleton pattern, just a class that cannot be instantiated with some class constants and methods. I would call that a static class (or something like that), not a singleton.

And why did you choose to call the method inherit? Wouldn’t sup or super or parent be a better name?

Apart from that I like the work you’ve done very much, especially the clear examples.

  • Comment by: Mislav
  • Posted:

Comment: #15

Dean, I never thought you want to compete with prototype.js, and I am certainly not a “XY already has this, no need for this” fan-boy. Sorry if this is what it looked like.

More choices are good, and one can always learn from other code, especially if it is yours, and adapt ideas. So thank you for sharing some of your work once again.

  • Comment by: Martin Bialasinski
  • Posted:

Comment: #16

[...] art man, and wasn’t happy with any Base classes out there in various libraries so he wrote his own Base.js. His goals: I want to easily create classes without the MyClass.prototype [...]

  • Pingback by: Ajaxian » Dean Edwards and Another Base.js
  • Posted:

Comment: #17

var Animal = Base.extend({
	constructor: function(name) {
		this.name = name;
	},

	say: function(message) {
		alert(this.name + ": " + message);
	}
});

Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-TW; rv:1.7.12) Gecko/20050919 Firefox/1.0.7

  • Comment by: modi
  • Posted:

Comment: #18

Nice work.

In the private data example, did you mean to use just ‘radius’ in the formula instead of ‘this.radius’, as in…

var Circle = Shape.extend({
	constructor: function(radius) {
		this.extend({
			getCircumference: function() {
				return Math.PI * radius * radius;
			}
		});
	}
});
  • Comment by: Steve Yen
  • Posted:

Comment: #19

@modi – Fixed now. Thanks for letting me know. I had to rename a variable from prototype to _prototype in a couple of functions. Presumably this is a bug that has been fixed in later versions of Firefox.

  • Comment by: -dean
  • Posted:

Comment: #20

@Jeremy/Mislav – I’ve changed the text of the post. I now use the expressions “override” and “single instance”. Thanks for correcting my poor use of computing terminology. spacer

@Steve – Fixed now. Thank you.

  • Comment by: -dean
  • Posted:

Comment: #21

Just a detail… I think inherit should be called something different. (It’s a semantic thing only, nothing wrong with the code in itself)

When you call baseclass.extend it is correctly a verb and your action is that expressed by the verb: extending your base class. But if I understood this correctly, when you call this.inherit you’re not really inheriting something, but actually calling the inherited method. The difference is subtle, I know, but it somehow doesn’t seem completely right.

I might suggest inherited instead, if you want to keep the inherit root, or something along the lines of what Mislav suggested above.

  • Comment by: Gonzalo
  • Posted:

Comment: #22

What do others think of the name inherit? Any other ideas? ancestor? I don’t like the other suggestions much (inherited, parent, sup) and super is already a reserved word.

  • Comment by: -dean
  • Posted:

Comment: #23

I have a couple of questions:

Whats the use of “…If you define a class method (not an instance method!) called init then will it …”, I thought thats what the constructor method was for.

Also this may be a newb question but when you stated that the ‘… second parameter passed to the extend method of a class defines the class interface’ in your example does is the PI property set the to Shape class?

- Thank you for all your contributions spacer

  • Comment by: John
  • Posted:

Comment: #24

BTW – I like ‘ancestor’ it gives me a better since of what its doing

  • Comment by: John
  • Posted:

Comment: #25

Douglas Crockford proposed a long time ago the word uber. I’m not really sure I like it, but there it is anyway.

I do like ancestor. parent is ok too.

  • Comment by: Gonzalo
  • Posted:

Comment: #26

@John – You can pass two parameters to class.extend. These parameters should be object literals. The first parameter defines the instance interface of the class. The second defines the class interface itself. You can perform class initialisation (rare but sometimes needed) by defining an init method on the class interface. This method will be called immediately the class is created. This is very different to the constructor function.

Below is a more detailed example. Class initialisation is required here because we need to close all open files when the document is unloaded. So we define an init method which adds an event handler:

var File = Base.extend({ // instance interface
	constructor: function(name, mode) {
		this.name = name;
		this.$guid = System.register(this);
		if (mode) this.open(mode);
	},

	$guid: 0,
	mode: 0,
	name: "",

	close: function() {
		delete File.opened[this.$guid];
		this.mode = 0;
	},

	open: function(mode) {
		this.mode = mode || File.READ;
		File.opened[this.$guid] = this;
	},

	read: function() {
	},

	write: function() {
	}
}, { // class interface
	CLOSED: 0,
	READ: 1,
	WRITE: 2,

	opened: {},

	closeAll: function() {
		var files = this.opened;
		for (var i in files) files[i].close();
	},

	init: function() {
		// class initialisation
		Event.add(window, "unload", this.closeAll, this);
	}
});

Does that makes sense? If you are not sure then ignore class initialisation. spacer Like I said, it is rarely need.

  • Comment by: -dean
  • Posted:

Comment: #27

As for the name: inherited() looks like a test that returns a bool. Aside: I like that ruby allows questionmarks in names, like “SomeObject.inherited?”

“parent()” is nice, but might be too often used already in objects (to express the relationship between two objects like in the DOM).

Nice example in #26. Shows of the lib quite well. The class / instance interface distinction is very neat.

  • Comment by: Martin Bialasinski
  • Posted:

Comment: #28

So the init is similer to the

var foo = Class.create(); Object.extend(foo,{

initialize: function(){ … } });

of Prototype?

  • Comment by: John
  • Posted:

Comment: #29

foo = Base.extend({
constructor: function(){
this.bar = 3;
},
bar = 3 },

{
init: function(){
this.bar = 3;
},
bar = 3
});

In this example I have set bar in alot of places. In both the instance and class interface. Also in the construcor and init methods. They all do the same thing right?

If I only did it in the constructor method would alert(foo.prototype.bar); // still show 3

So I guess I dont see the need for an instance interface and a class interface, don’t they both do the exact same thing?

  • Comment by: John
  • Posted:

Comment: #30

BTW thank you for taking your time to help and show examples spacer

  • Comment by: John
  • Posted:

Comment: #31

@John – You’ve missed the point slightly. Have another look at the example I posted.

  • Comment by: -dean
  • Posted:

Comment: #32

More suggestions instead of “inherited”:

And all those suggesions prepended w/ “call”, so “callBase”.

  • Comment by: Jeremy Dunck
  • Posted:

Comment: #33

Err, any chance of this being made MIT, BSD, AFL, or similar? LGPL? Really?

  • Comment by: Jeremy Dunck
  • Posted:

Comment: #34

Hey, since this is a “refactored” version of common are we going to see an IDE? That was a fun project I thought (more so since I’ve started playing with smalltalk)

Anyway, Base is nice. I do agree with the folks that think the “inherit” method seems oddly named. I say forget all that tired language of “super”, “parent” or “inherit” and go with something new. I like “basis” as it goes well with the name Base. Mmm… “basis”

  • Comment by: mitchell
  • Posted:

Comment: #35

So I just answered my own question about the IDE. I looked through your development area, and was stoked to see all that. Nice work! How long have you been at this? This has way more written on top of it then common ever did.

  • Comment by: mitchell
  • Posted:

Comment: #36

@Jeremy – I’ll look at changing the license for this.

@Mitchell – Yes, common was fun and I managed to write at least one complex application using it. Base is more cross-browser. The IDE is unfinished. The IDE is useful for browsing object hierarchies but less useful for actually writing code. Until someone writes a decent text editor that is…

And you are right. The IDE is based on Smalltalk. spacer

  • Comment by: -dean
  • Posted:

Comment: #37

Very nice. Not sure if I will use it since I’ve already written so much of my code using prototype but this is the cleanist implementation of class based OO I’ve yet seen.

I was a bit unclear about the point of the _static argument (i.e. second argument in Base.extend( , ) ). It seems to add methods just to the class but not to any instance variables but it also doesn’t seem to be inherited. Is this the intended behavior or am I just missing something in the code? I guess I’m just a bit confused as to what sort of OO model you have in mind with the static stuff.

One thought for future improvement. It seems possible that if you use object.extend inside an event handler or more likely the return from an XHR the global flag Base._prototyping could cause some problems. It seems possible to instead avoid the problem of calling the initializer when you new this by instead copying this to a temp variable renaming the constructoring calling new and then returning the constructor. However, maybe I am missing something.

  • Comment by: logicnazi
  • Posted:

Comment: #38

@logicnazi – It is my intention that static methods and properties are not inherited. I’ve provided this mechanism mainly for the provision of class constants. Look at JavaScript’s Number class as an example of what I mean:

phrogz.net/ObjJob/object.asp?id=172

As to your other point. The Base._prototyping flag is only set when creating a class. It is not set when using object.extend.

  • Comment by: -dean
  • Posted:

Comment: #39

Hmm… feels a lot like the Dojo toolkit’s ‘dojo.lang.extend’, except they’re missing a lot of the extended functionality you’re providing.

Might be worth a look, though, as you seem to be on the same track: manual.dojotoolkit.org/lang.html

  • Comment by: James Bennett
  • Posted:

Comment: #40

Ohh right I see about the _prototyping flag. I retract my point. It would be kinda wastefull to add all that code for the crazy situation where people are defining new classes in event handlers.

Okay, now I understand what you meant by static. I was just a bit confused by the terminology.

Thanks alot for your response not to mention the library.

  • Comment by: logicnazi
  • Posted:

Comment: #41

If I try to pass a function in a class, I lose the properties of that class. Any idea why?

var obj = new Base;
obj.extend({
	val    : 5,
	method : function(){ alert(this.val); }
});

var myMethod = obj.method;

obj.method(); // 5
myMethod();   // undefined
  • Comment by: Mark Kahn
  • Posted:

Comment: #42

Mark – this is what should happen. When you call myMethod, the this value is pointing to the global (window) object. Because there is no window.val defined the function returns undefined.

  • Comment by: -dean
  • Posted:

Comment: #43

@Mark:

Javascript “methods” are just functions hanging off an object– the “this” keyword isn’t bound to the object if you don’t scope it with the “.” operator.

Check out Boodman’s “hitch” function (which he called “close” in that post) — it makes the function do what you want

function hitch(obj, methodName) {
  return function() { 
    obj[methodName].apply(obj, arguments);
}

(from youngpup.net//2005/0525024806/comments#c1444 )

You’d change this line:

var myMethod = obj.method;

to this:

var myMethod = hitch(obj,’method’);

  • Comment by: Jeremy Dunck
  • Posted:

Comment: #44

Hello.

Great tool Dean, I like it and I will start using it. Thanks.

Just two comments:

Thanks for your attention.

  • Comment by: knocte
  • Posted:

Comment: #45

I have already converted IE7, packer and my syntax highlighter to Base. I haven’t released any of this code yet. Some of the classes are here:

dean.edwards.name/base/text/src/

  • Comment by: -dean
  • Posted:

Comment: #46

Dean, I saw that you mentioned that you didn’t want to mess with the Object.prototype. Have you considered muffing with the Function.prototype instead? Like…something like this:

Function.prototype.method = 
	function (name, func) { 
		this.prototype[name] = func; 
		return this; 
	};

This typically shows up in Crockford’s toolkit and I’ve found it to be pretty nice.

  • Comment by: Dustin Diaz
  • Posted:

Comment: #47

[...] ebdesign imagereplacement) gotAPI.com :: API lookup service (tags: reference html css) A Base Class for JavaScript Inheritance (tags: javascript oop) [...]

  • Pingback by: BarelyBlogging » Blog Archive » links for 2006-04-08
  • Posted:

Comment: #48

@Dustin – Yeah, this was the way I wrote it originally. But adding an override capability meant that I had to add the inherit mechanism too. It felt too much like I was extending the language rather than just adding a new class.

  • Comment by: -dean
  • Posted:

Comment: #49

Dean, how would you use your library for implementing a class that contains both static and non-static members and properties in a class?

  • Comment by: Ympostor
  • Posted:

Comment: #50

@Ympostor – An example of a class with both a class and instance interface is shown in Comment #26.

  • Comment by: -dean
  • Posted:

Comment: #51

neat! the inherit() method is really useful but has been missing badly in other libs i have come across. don’t really like the name though. i vote for base() or super().

  • Comment by: oak
  • Posted:

Comment: #52

Nobody likes inherit except me :-(.

super is already a reserved word. These are the alternatives that I like:

I’m still undecided…

  • Comment by: -dean
  • Posted:

Comment: #53

What about polymorphism?

I implemented a fully supported but complicated Object Oriented JavaScript library: j2s.sourceforge.net/j2sclazz/ And the article: j2s.sourceforge.net/articles/oop-in-js-by-j2s.html

It seems it also fits all of your requirements of OO.

  • Comment by: Josson Smith
  • Posted:

Comment: #54

Wh

gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.