Posted by Charlie
Fri, 01 Feb 2008 08:22:00 GMT
Maybe its just me, but what I want from a JavaScript library seems to be diverging from what Prototype provides. What I want, in order of importance, is:
- A cross-browser API that hides some of the major differences between Internet Explorer and standards compliant browsers
- Unobtrusive
- As small as possible, and if that's not possible, then at least modular
- A selector API
Where Prototype really falls down is on points two and three - its very obtrusive, getting larger by the day and isn't modular.
Accepting Something for What It Is
Prototype's greatest sin is its disdain for JavaScript.You can see this disdain shine through in a number of ways.
First, Prototype originated as part of Rails, which provides helpers that use Ruby code to generate JavaScript. If programs could talk, Rails would be saying "Let me take care of this for you since you certainly don't want to dirty your hands with JavaScript."
Second, Prototype wastes over 200 lines of code (about 5%) duplicating Ruby's Enumerable API in JavaScript, for no obvious reason except the developers prefer Ruby's way of doing things. The problem is that Ruby's Enumerable API is based on one of the core features of Ruby - its elegant use of anonymous functions (called blocks) to apply snippets of code to a sequence of items. JavaScript has first-class anonymous functions, but it doesn't have the language support for using them as iterators. As a result, Prototype's JavaScript code doesn't look natural because it is working outside the design strengths of JavaScript. And more importantly, it forces Prototype into using exceptions as a iteration signaling method, which is a nasty hack.
For example, let's look at the any method. In Ruby, any? returns true if an item in a list matches some criteria. Thus to find if any number in an array is odd you would write this:
[2, 4, 6, 8, 11].any? do |value|
value.even? # even? is from Rails, not Ruby
end
In my view, porting any to JavaScript is of dubious value at best. But let's look at the contortions that Prototype has to go through to do it:
any: function(iterator, context) {
iterator = iterator ? iterator.bind(context) : Prototype.K;
var result = false;
this.each(function(value, index) {
if (result = !!iterator(value, index))
throw $break;
});
return result;
}
each: function(iterator, context) {
var index = 0;
iterator = iterator.bind(context);
try {
this._each(function(value) {
iterator(value, index++);
});
} catch (e) {
if (e != $break) throw e;
}
return this;
}
_each: function(iterator) {
for (var i = 0, length = this.length; i < length; i++)
iterator(this[i]);
}
The any method calls each with calls _each which then calls your method. And since JavaScript doesn't support returning values from an anonymous function used as an iterator (there is no yield keyword like in Ruby), the any method is forced to throw an exception (see $break) to signal that an element has been found. That might seem like a small offense until you are trying debug JavaScript code using Venkman and keep interrupted by meaningless exceptions (which happens if you've asked Venkman to stop at all errors and exceptions).
More examples of trying to make JavaScript more like Ruby abound:
- The addition of a Class object that introduces an initialize function, instead of just accepting JavaScript's combined constructor/initalizer idiom
- A number of useless additions to the String class (methods like succ, times, etc) - 100 plus lines of code
- A number of useless additions to the Array class (methods like succ, times, etc) - a bit less than 100 lines of code
The end result is that over 10% of Prototype is wasted trying to add Ruby like-features to JavaScript that don't fit well, simply because the Prototype designers prefer Ruby's idioms over JavaScript's idioms. The obvious problem is that Prototype is a JavaScript library, not a Ruby library.
Lay Off My Prototypes
Prototype also fails miserably on the unobtrusive test. In its first version, Prototype added methods to JavaScript's Object prototype - which is a big no-no. Not learning from its past mistakes, the latest version of Prototype has this gem:
(function() {
var element = this.Element;
this.Element = function(tagName, attributes) {
attributes = attributes || { };
tagName = tagName.toLowerCase();
var cache = Element.cache;
if (Prototype.Browser.IE && attributes.name) {
tagName = '<' + tagName + ' name="' + attributes.name + '">';
delete attributes.name;
return Element.writeAttribute(document.createElement(tagName), attributes);
}
if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName));
return Element.writeAttribute(cache[tagName].cloneNode(false), attributes);
};
Object.extend(this.Element, element || { });
}).call(window);
Take a good, long look at this method. It replaces a browser's built in Element object, which is used to represent elements in a DOM tree, with an Element function. Replacing a core browser object is nuts. Especially for the ridiculously small payoff. Instead of writing this:
var element = document.createElement('foo')
element.id = 7
This change lets you write this:
var element = new Element('foo', {id: 7})
And how many times does Prototype use this function? A measly 4 times! And to add insult to injury, the code as written is broken because it breaks the prototype chain. The last line in the function should be:
this.Element.prototype = element.prototype
Without this line, any custom extensions you've made to the Element object are lost. Trust me, it took a good long time to debug why our code no longer worked.
Time for a Diet
Finally, Prototype is getting bigger with every release. Version 1.5 weighs in at 3,396 lines of code while version 1.6 is 4,307 lines, a 27% increase. I'm sure the additional code is useful, but I'm also sure there are great swaths of Prototype that I don't need. Unfortunately, Prototype doesn't provide a mechanism to package up only the parts of it you want. When the library was smaller, that was a reasonable decision. But as Prototype continues to grow, there will come a point where its benefits are outweighed by its weight (and for me I've passed that point).
So What Next
The last few years have been JavaScript's golden years, marked by an amazing outpouring of experimentation and creativity that has led to a number of great JavaScript libraries. A huge benefit of this work is revealing the pain points, beyond cross-browser compatibility issues, of working with JavaScript. These issues include the lack of a Selector API, better iterators, better chaining of DOM methods, wordy method names (getElementById), etc.
Of course each library takes its own approach to solving these problems, and with that comes a downside - lockin. For large JavaScript projects, switching between libraries is a boring, tedious, time-consuming undertaking. Which is the reason we've remained with Prototype for as long as we have and will continue to do so for a bit longer while we plan our migration to a new library.
Posted in JavaScript | 15 comments | 1 trackback
Posted by Charlie
Wed, 13 Jun 2007 21:30:00 GMT
Update - Armin has an alternate implementation based on some fancy regular expressions combined with String's split method. Its supports most of ERB and avoids all the string mashing I do. Nice!
Templating engines are the most popular way to generate HTML pages and other web content. First popularized by PHP and ASP , templating engines allow you to mix code and content. The templating engine then takes the combined content, extracts the code, runs it, and combines the results with the remaining content to produce the final output.
Since templating engines are generally used to create HTML that is displayed by a browser, they are almost always run on a server. But now that all modern browsers support the DOM, XML and Ajax, it can be helpful to run a templating engine on the client.
Before continuing, remember that JavaScript templates are often not the right solution. Alternatives include generating HTML on a server, or if you are using XML, to use XSL on the client or server to generate HTML.
But if you need something simple and light, perhaps to display a JSON result returned by an Ajax request, then JavaScript templates may fit the bill.
Writing the Templating Engine
A quick search on the Internet found a few existing engines, such as JavaScript Templates, Ajax Pages and the Prototype library. However, I found the first two to be a bit heavyweight while Prototype was a bit to simple (it only supports the replacement of values, not the execution of arbritrary statements such as for loops). So I decide to roll my own.
Creating a template engine in JavaScript is remarkably easy due to the power of String's replace method. One of its lesser known features is that you specify a function to invoke every time a pattern is matched. The pattern is replaced by the results of the invoked function. Using replace, you can write a template compiler in ten lines of code (and undoubtedly less if you wanted to).
The whole templating engine weighs in at 90 lines, including a helper function copied from the Prototype library. The engine defines two objects - a template object and a parser object. The template object takes a string that includes mixed code and content, invokes the parser to compile the template, and then evaluates and returns the result.
Using the Templating Engine
To see how this works, I've created a simple example that is online. If you look at the HTML code, you'll see:
function replaceContent()
{
var colorsArray = ['Red', 'Green', 'Blue', 'Orange']
var source =
'<p>Here is a list of <%= this.colors.length %> colors:' +
' <ul>' +
' <% for (var i=0; i<this.colors.length; i++) { %>' +
' <li><%= this.colors[i] %></li>' +
' <% } %>' +
' </ul>' +
'</p>'
var template = new JsTemplate.Template(source)
var content = template.run({colors: colorsArray})
var element = document.getElementById('content')
element.innerHTML = content
}
The first thing to notice is that the source variable specifies the mixed code and content. The syntax is similar to ERB, which is a Ruby templating engine. The two recognized tags are:
<% %> Run JavaScript code
<%= %> Replace JavaScript code with the result
To create your own tags create a new Parser object with an appropriate regular expression.
The second thing to notice is that the data use by the template engine is specified via a parameter to the run method. The parameter should be a JavaScript object. The properties of the object are copied to the template object, thus allowing the template to refer to them via the this keyword. And that is about it (I said it was lightweight!).
To source code of the templating engine is here, while the example is here. Note the code is released under an MIT license, so you can use it however you would like. Enjoy.
Posted in JavaScript, Programming, Web | 6 comments | 1 trackback
Posted by Charlie
Tue, 12 Jun 2007 23:20:00 GMT
Opera 9 is a great browser - it small, standards compliant and fast. And not just slightly faster - really fast (I don't believe Apple's browser speed comparision they've put up with the Safari 3 Beta - its not what I've seen in the real world).
For example, out of the box its ten times faster than Firefox at rendering complex SVG drawings. IIt almost fast enough that creating SVG maps is plausible...ah well...skip that...but that is for another post. Anyway, I'll let you in on a little secret - Firefox's rendering performance is salveagable - go read SVG's suspendRedraw and unsuspendRedrawAll apis..
Hashing up Ajax
However, Opera has one awful gotcha - you cannot return an HTTP status code other than 200 in an Ajax request and get the response body back. You might be thinking that's awfully obscure, but its not.
For example, say your server supports the Atom Publishing Protocol. When a user POSTs a new resource to your server, its job is to return a representation of the new resource with an HTTP status code of 201 CREATED. So something like this:
HTTP/1.1 201 Created
Date: Fri, 7 Oct 2005 17:17:11 GMT
Content-Length: nnn
Content-Type: application/atom+xml;type=entry;charset="utf-8"
Location: http://example.org/edit/first-post.atom
ETag: "c180de84f991g8"
<?xml version="1.0"?>
<entry xmlns="http://www.w3.org/2005/Atom">
<title>Atom-Powered Robots Run Amok</title>
<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
<updated>2003-12-13T18:30:02Z</updated>
<author><name>John Doe</name></author>
<content>Some text.</content>
<link rel="edit"
href="http://example.org/edit/first-post.atom"/>
</entry>
Except Opera won't return the result! If you check the XmlHttpRequest's responseText or responseXML attributes they are NULL. This is problematic, because the response contains valuable information - such as the ID the server has assigned the new entry.
It also means you can't use standard error codes if your client needs access to the response body.
The Frustration of it All
What's galling about this bug is that its most likely caused by an if statement deep in the bowls of the Opera that intentionally throws away the result when the status code is not 200! Thus, its probably a simpe fix...which leads to the next frustration.
As good as Opera's browser is, its bug tracking sytem is as bad. I submitted a bug about this over a year ago and obviously it hasn't been fixed. I can live with that, but it sure would be nice to see its current status.
Except Opera hides its bug reports, like many other companies. I've never understood the logic of this. I've heard the argument that a bug report could contains information that could competitively disadvantage a company - but how often does that really happen? And when it does, just delete the information - you do read your bug reports, right!
I think the real reason is that corporations don't like to appear fallible, and bugs are obvious, small failures. However hiding them does not make them go away - instead it just frustrates users. Everyone knows software has bugs - so why not face up to the truth?
So to change the world in my own small way, MapBuzz's bug reports are public and always will be.
And that's the end of today's rant :)
Posted in JavaScript, Programming, Web | 2 comments | no trackbacks
Posted by Charlie
Tue, 08 May 2007 19:06:00 GMT
Now that you've launched your new killer Web 2.0 website, how do you detect errors in your deployed Javascript?
Using onerror
The standard approach is to hook into the Window object's onerror event handler and use Ajax to log your requests to the server. There are some good tutorials on the web on how to do this, but here is one approach:
// Register global error handler
window.onerror = function(message, uri, line)
{
var fullMessage = message + "\n at " + uri + ": " + line
remoteLogger.log(fullMessage)
// Let the browser take it from here
return false
}
Notice that you have to explicity set window.onerror using old-style event handlers, attachEvent and addEventListener don't seem to do the trick. Also, Internet Explorer always stupidly sets the URI parameter to the URI of the current page, not the file that caused the problem. Thus you have to hunt through all the linked Javascript files looking at the specified line number and make a best guess as to which file caused the problem.
Getting a Stack Trace
Often times knowing where an error occurred is not enough - what you really need is the full stack trace. If your user has a Gecko based browser (eg, Firefox), you're in luck.
Notice the stack parameter in the code above? Gecko has a poorly documented stack property on the global Error object that provides just what we need.
Let's say you have code that looks like this:
function first()
{
second()
}
second = function()
{
blowUp()
}
function blowUp()
{
try
{
foo.bar()
}
catch (e)
{
handleException(e)
}
}
If you call the first method, say from onload like in this example, the resulting stack trace is:
blowUp()@file:///C:/temp/error.js:17
()@file:///C:/temp/error.js:10
first()@file:///C:/temp/error.js:
onload([object Event])@file:///C:/temp/error.html:1
@:0
Each line has the following format:
<method_name>(<arguments>)@<uri>:<line_number>
Notice that the method_name will be blank for anonymous functions, which are quite common if you follow the prototype javascript style.
A Simple Logger
Now let's take a look at some code. First, here is a simple logger that posts errors to a server via Ajax (note this code assumes your are using the prototype library):
RemoteLogger = function RemoteLogger()
{
this.logging = false
}
Object.extend(RemoteLogger.prototype,
{
log: function(message, stack)
{
if (!this.logging)
{
this.logging = true
var parameters = 'resource=error'
var postBody = 'error=' + encodeURIComponent(message) +
'&stack=' + encodeURIComponent(stack)
var requestOptions =
{
method: 'post',
parameters: parameters,
postBody: postBody,
onSuccess: function(transport)
{
this.logging = false
}.bind(this)
}
new Ajax.Request('/logger', requestOptions)
}
}
})
Handling Exceptions
Next, let's define the handleException method we used above. This method extracts out useful information from an Error object and uses the logger above to post the results to a server.
function handleException(exception)
{
/* In FF exception can be a string if it happens
when opening the xmlHttpRequest. Gah! */
if (typeof exception == 'string')
exception = new Error(exception)
/* If a xmlhttp request is happening in Mozilla and
the user navigates to another page, then when
the first request returns a NS_ERROR_NOT_AVAILABLE
error will be thrown. So just ignore it. */
if (exception.name == 'NS_ERROR_NOT_AVAILABLE') return
var fullMessage = ''
var uri = ''
var stack = ''
var line = ''
try
{
/* Don't use exception.toString since the JS spec
does not require it to provide the error name or message
(haven't tested to see if it matters though across browsers) */
fullMessage = exception.name + ': ' + exception.message
uri = exception.fileName
stack = exception.stack
// Firefox sometimes blows up here
line = exception.lineNumber
}
catch (e)
{
}
fullMessage += "\n at " + uri + ": " + line
console.info(fullMessage)
console.info(stack)
remoteLogger.log(fullMessage, stack)
}
Annoying Gotchas
There are few annoying gotchas to know about:
- Stack traces are only available from Error objects thrown by exceptions and thus are not available from the onerror method.
- Uncaught exceptions are not hanlded by onerror.
- There is no global exception handler in Javascript, so you have to be very careful in the way you right your code. On the positive side, its easy to implement a global error handler for methods that are invoked due to the results of an Ajax request. On the other hand, its much harder to do this for methods invoked due to normal events generated by a user interacting with the browser.
Anyway, the more information you can get about browser errors the better - you'll often be surprised by the results!
Posted in JavaScript, Programming, Web | no comments | no trackbacks
Posted by Charlie
Fri, 25 Aug 2006 21:48:00 GMT
Last time
I talked about my implementation of JavaScript inheritance. Since then I've
made a number of improvements - its now simpler, faster
and easier to use.
In my post I pointed out some alternative, including
one from Kevin
Lindsey. Kevin's implementation is my favorite because its the simplest
and least intrusive solution.
It turns out our two implementation are quite
similar - the main difference is that I added in a a callSuper method. This
might not seem like much, but let's look at an example to see how is dramatically
changes the code you write.
Let's assume we have a Pet object that
inherits from a Animal object (I don't use "class" since JavaScript
doesn't have classes, just prototypes).
Here is how you would code in using Kevin's implementation:
function Pet(owner, name)
{
this.owner = owner
Pet.baseConstructor.call(this, owner, name)
}
KevLinDev.extend(Pet, Animal)
Pet.prototype.toString = function()
{
return Pet.superClass.toString.call(this) + "\n" +
"My owner is " + this.owner
}
Notice three things. First, the name of the current class is hard-coded into
methods (for example, look at Pet.baseConstructor). Second, calling
an overridden constructor (Pet.baseConstructor for example) is
different than calling an overridden method (Pet.superClass).
Last, invoking a super method requires using JavaScript's call function instead
of a normal method call.
Now let's add in a callSuper method and see what the code looks like:
function Pet(owner, name)
{
this.owner = owner
this.callSuper(arguments.callee, name)
}
Pet.inherits(Animal)
Pet.prototype.toString = function()
{
return this.callSuper(arguments.callee) + "\n" +
"My owner is " + this.owner
}
We've gotten rid of all the limitations mentioned above - but
have added two.
This first is the need to pass arguments.callee as the first
parameter. This is used by callSuper to determine the currently
executing method. Without this information, callSuper cannot lookup
the overridden super method.
In previous versions of JavaScript you don't need this parameter
because you could determine what method invoked a method by arguments.callee.caller.
However, caller
has been deprecated in JavaScript. Thus this works in Firefox
and Internet Explorer but not Safari, Konqueror, and if
I remember correctly, Opera.
The second limitation is hidden - using callSuper introduces a performance
hit since it has to look up the calling method (a consequence of caller
being deprecated). However, in my new improved implementation this performance
hit has been eliminated for some common cases and in other cases it has been
reduced by 50%. Thus it only comes into play if you're creating hundreds and
hundreds of objects.
Updated Implementation
So let's look at the new implementation:
http://www.opensource.org/licenses/bsd-license.php
Function.prototype.inherits = function(superConstructor)
{
function CreatePrototype() {}
CreatePrototype.prototype = superConstructor.prototype
this.prototype = new CreatePrototype()
this.prototype.constructor = this
this.superConstructor = superConstructor
this.prototype.callSuper = function()
{
var caller = arguments[0]
var args = new Array()
for (var i=1; i<arguments.length; i++)
args.push(arguments[i])
var currentConstructor = this.constructor
var methodName = null
while (methodName == null && currentConstructor != null)
{
if (caller === currentConstructor)
return currentConstructor.superConstructor.apply(this, args)
methodName = figureMethodName(currentConstructor.prototype, caller)
currentConstructor = currentConstructor.superConstructor
}
if (!methodName)
throw new Error("Could not find method: " + methodName + ".")
if (!currentConstructor)
throw new Error("Prototype does not have an ancestor: "
+ currentConstructor + ".")
return currentConstructor.prototype[methodName].apply(this, args)
}
}
function figureMethodName(prototype, method)
{
for (var key in prototype)
{
if (prototype.hasOwnProperty(key) &&
prototype[key] === method)
return key
}
return null
}
And here is an example of using it:
function Animal(name)
{
if (!name)
throw new Error('Must specify an animal name')
this.name = name
}
Animal.prototype.toString = function()
{
return 'My name is ' + this.name
}
function Pet(owner, name)
{
this.owner = owner
this.callSuper(arguments.callee, name)
}
Pet.inherits(Animal)
Pet.prototype.toString = function()
{
return this.callSuper(arguments.callee) + "\n" +
"My owner is " + this.owner
}
function Cat(owner, name)
{
this.callSuper(arguments.callee, owner, name)
}
Cat.inherits(Pet)
Cat.prototype.toString = function()
{
return this.callSuper(arguments.callee) + '\n' +
'I eat mice'
}
var cat = new Cat('charlie', 'oba')
alert(cat.toString())
CreatePrototype
The first thing that might look suspicious is CreatePrototype.
This is a brilliant idea I borrowed from Kevin. It neatly solves a common problem
that bites all new JavaScript developers - and sometimes experienced
ones who are forgetfully like yours truly!
Take a look at the Animal constructor:
function Animal(name)
{
if (!name)
throw new Error('Must specify an animal name')
this.name = name
}
In traditional JavaScript inheritance, to have Pet inherit from Animal, you'd
write the following code:
Pet.prototype = new Animal()
Pet.prototype.constructor = Pet
When we try to create a new Animal as a prototype, the Animal constructor
will throw an exception because it was not passed a name. To avoid this, you
have to sprinkle ugly if-statements throughout your constructors to protect
code that should only be called when creating a new instance versus prototypes.
CreatePrototype solves the whole mess because it entirely skips
calling the Animal constructor. Instead, new CreatePrototype() creates
a blank new object. However, that object's __proto__ property is set to the
Animal's prototype thereby inheriting all its methods which
is exactly what we want.
Let's look at a diagram to see what this looks like:

The gray boxes with capital letters are constructors (JavaScript functions)
while the blue objects with underlined letters are instance of objects.
By using CreatePrototype(), we replace animal with createPrototype which
is nothing more than a blank object. But notice that the __proto__ properties
are still correctly setup.
callSuper
So how does callSuper work?
First, we need to determine the name of the method being currently executed
and what prototype contains it. Let's use Cat.toString as an example - its
defined as an anonymous function so it doesn't actually have a name. Thus the
need for the ugly callee parameter, which is pointer to the currently executing
method:
Cat.prototype.toString = function()
{
return this.callSuper(arguments.callee) + "\n" + "I eat mice"
}
Starting at the Cat prototype we climb up the inheritance tree until we
find the calling method. To do this, we call figureMethodName for each prototype,
specifying the current prototype and method (i.e., caller).
function figureMethodName(prototype, method)
{
for (var key in prototype)
{
if (prototype.hasOwnProperty(key) &&
prototype[key] === method)
return key
}
return null
}
The call to hasOwnProperty is quite important - we only want
to return methods defined on the current prototype. If we return a method defined
by a super class, then we'll end up with infinite recursion. That happens
because we'll end up calling the method on a child prototype instead of the
super prototype. Thus, when callSuper is invoked again we'll end up back in
the same place (remember that each time we invoke callSuper we start at the
bottom of the inheritance chain because this always refers
to the current JavaScript object).
Once we've found the method name, then we simply invoke it on the superConstructor
and let JavaScript do the rest.
Here is the updated code - and as usual all feedback is welcome.
Posted in JavaScript, JavaScript | no comments | no trackbacks
Posted by Charlie
Fri, 25 Aug 2006 21:48:00 GMT
Last time
I talked about my implementation of JavaScript inheritance. Since then I've
made a number of improvements - its now simpler, faster
and easier to use.
In my post I pointed out some alternative, including
one from Kevin
Lindsey. Kevin's implementation is my favorite because its the simplest
and least intrusive solution.
It turns out our two implementation are quite
similar - the main difference is that I added in a a callSuper method. This
might not seem like much, but let's look at an example to see how is dramatically
changes the code you write.
Let's assume we have a Pet object that
inherits from a Animal object (I don't use "class" since JavaScript
doesn't have classes, just prototypes).
Here is how you would code in using Kevin's implementation:
function Pet(owner, name)
{
this.owner = owner
Pet.baseConstructor.call(this, owner, name)
}
KevLinDev.extend(Pet, Animal)
Pet.prototype.toString = function()
{
return Pet.superClass.toString.call(this) + "\n" +
"My owner is " + this.owner
}
Notice three things. First, the name of the current class is hard-coded into
methods (for example, look at Pet.baseConstructor). Second, calling
an overridden constructor (Pet.baseConstructor for example) is
different than calling an overridden method (Pet.superClass).
Last, invoking a super method requires using JavaScript's call function instead
of a normal method call.
Now let's add in a callSuper method and see what the code looks like:
function Pet(owner, name)
{
this.owner = owner
this.callSuper(arguments.callee, name)
}
Pet.inherits(Animal)
Pet.prototype.toString = function()
{
return this.callSuper(arguments.callee) + "\n" +
"My owner is " + this.owner
}
We've gotten rid of all the limitations mentioned above - but
have added two.
This first is the need to pass arguments.callee as the first
parameter. This is used by callSuper to determine the currently
executing method. Without this information, callSuper cannot lookup
the overridden super method.
In previous versions of JavaScript you don't need this parameter
because you could determine what method invoked a method by arguments.callee.caller.
However, caller
has been deprecated in JavaScript. Thus this works in Firefox
and Internet Explorer but not Safari, Konqueror, and if
I remember correctly, Opera.
The second limitation is hidden - using callSuper introduces a performance
hit since it has to look up the calling method (a consequence of caller
being deprecated). However, in my new improved implementation this performance
hit has been eliminated for some common cases and in other cases it has been
reduced by 50%. Thus it only comes into play if you're creating hundreds and
hundreds of objects.
Updated Implementation
So let's look at the new implementation:
http://www.opensource.org/licenses/bsd-license.php
Function.prototype.inherits = function(superConstructor)
{
function CreatePrototype() {}
CreatePrototype.prototype = superConstructor.prototype
this.prototype = new CreatePrototype()
this.prototype.constructor = this
this.superConstructor = superConstructor
this.prototype.callSuper = function()
{
var caller = arguments[0]
var args = new Array()
for (var i=1; i<arguments.length; i++)
args.push(arguments[i])
var currentConstructor = this.constructor
var methodName = null
while (methodName == null && currentConstructor != null)
{
if (caller === currentConstructor)
return currentConstructor.superConstructor.apply(this, args)
methodName = figureMethodName(currentConstructor.prototype, caller)
currentConstructor = currentConstructor.superConstructor
}
if (!methodName)
throw new Error("Could not find method: " + methodName + ".")
if (!currentConstructor)
throw new Error("Prototype does not have an ancestor: "
+ currentConstructor + ".")
return currentConstructor.prototype[methodName].apply(this, args)
}
}
function figureMethodName(prototype, method)
{
for (var key in prototype)
{
if (prototype.hasOwnProperty(key) &&
prototype[key] === method)
return key
}
return null
}
And here is an example of using it:
function Animal(name)
{
if (!name)
throw new Error('Must specify an animal name')
this.name = name
}
Animal.prototype.toString = function()
{
return 'My name is ' + this.name
}
function Pet(owner, name)
{
this.owner = owner
this.callSuper(arguments.callee, name)
}
Pet.inherits(Animal)
Pet.prototype.toString = function()
{
return this.callSuper(arguments.callee) + "\n" +
"My owner is " + this.owner
}
function Cat(owner, name)
{
this.callSuper(arguments.callee, owner, name)
}
Cat.inherits(Pet)
Cat.prototype.toString = function()
{
return this.callSuper(arguments.callee) + '\n' +
'I eat mice'
}
var cat = new Cat('charlie', 'oba')
alert(cat.toString())
CreatePrototype
The first thing that might look suspicious is CreatePrototype.
This is a brilliant idea I borrowed from Kevin. It neatly solves a common problem
that bites all new JavaScript developers - and sometimes experienced
ones who are forgetfully like yours truly!
Take a look at the Animal constructor:
function Animal(name)
{
if (!name)
throw new Error('Must specify an animal name')
this.name = name
}
In traditional JavaScript inheritance, to have Pet inherit from Animal, you'd
write the following code:
Pet.prototype = new Animal()
Pet.prototype.constructor = Pet
When we try to create a new Animal as a prototype, the Animal constructor
will throw an exception because it was not passed a name. To avoid this, you
have to sprinkle ugly if-statements throughout your constructors to protect
code that should only be called when creating a new instance versus prototypes.
CreatePrototype solves the whole mess because it entirely skips
calling the Animal constructor. Instead, new CreatePrototype() creates
a blank new object. However, that object's __proto__ property is set to the
Animal's prototype thereby inheriting all its methods which
is exactly what we want.
Let's look at a diagram to see what this looks like:

The gray boxes with capital letters are constructors (JavaScript functions)
while the blue objects with underlined letters are instance of objects.
By using CreatePrototype(), we replace animal with createPrototype which
is nothing more than a blank object. But notice that the __proto__ properties
are still correctly setup.
callSuper
So how does callSuper work?
First, we need to determine the name of the method being currently executed
and what prototype contains it. Let's use Cat.toString as an example - its
defined as an anonymous function so it doesn't actually have a name. Thus the
need for the ugly callee parameter, which is pointer to the currently executing
method:
Cat.prototype.toString = function()
{
return this.callSuper(arguments.callee) + "\n" + "I eat mice"
}
Starting at the Cat prototype we climb up the inheritance tree until we
find the calling method. To do this, we call figureMethodName for each prototype,
specifying the current prototype and method (i.e., caller).
function figureMethodName(prototype, method)
{
for (var key in prototype)
{
if (prototype.hasOwnProperty(key) &&
prototype[key] === method)
return key
}
return null
}
The call to hasOwnProperty is quite important - we only want
to return methods defined on the current prototype. If we return a method defined
by a super class, then we'll end up with infinite recursion. That happens
because we'll end up calling the method on a child prototype instead of the
super prototype. Thus, when callSuper is invoked again we'll end up back in
the same place (remember that each time we invoke callSuper we start at the
bottom of the inheritance chain because this always refers
to the current JavaScript object).
Once we've found the method name, then we simply invoke it on the superConstructor
and let JavaScript do the rest.
Here is the updated code - and as usual all feedback is welcome.
Posted in JavaScript, JavaScript | no comments | no trackbacks
Posted by Charlie
Tue, 22 Aug 2006 05:27:00 GMT
This code has been deprecated - use the new and improved version instead.
I've always been a fan of JavaScript - its flexibility makes it
well tailored for its primary execution environment inside of web browsers.
It certainly counts as a language that gets
out of
your way.
As you probably know, JavaScript is based on prototypes.
What that means in practice is that you can change all existing instances of
an object at runtime, after they've been created, by adding or removing methods
from the object's prototype. You can also update a particular instance of an
object at runtime by manipulating just that object.
This capability is by no mean unique to JavaScript
- Ruby let's you do the same thing for example - but JavaScript is the most widely
deployed language that has this sort of flexibility. And I believe its the
only widely deployed prototype based language (anyone know of another that
is widely deployed?).
JavaScript Inheritance
Although JavaScript is fully object-oriented, its inheritance mechanism is
clunky. In fact, until the Ajax craze most people didn't even know that JavaScript
supported inheritance. Just look at the prototype library
- it defines an extend method that copies all the properties/method from one
object to another. Its a great example of JavaScript's flexibility, but not
a great example of software engineering.
The JavaScript 1.5 guide is
the place to learn how JavaScript's inheritance works. Its an updated version
of an old Netscape DevEdge article that
the Mozilla Foundation rescued from oblivion. I still
remember reading it back in 2000 - it was quite an eye opener - I hadn't realized
the power hiding within JavaScript.
Over the years a myriad of implementations have popped up to
simplify JavaScript inheritance. Some of the well known ones are from Douglas
Crockford, Kevin
Lindsey, Joshua Gertzen and Dean
Edwards. These are all fine implementations. They of course
differ somewhat in their capabilities and complexity.
My Take
A while back I put together my own implementation, but never published
it. Since my JavaScript posts seem to be pretty popular, I thought it was time
to open it up for review. Feel free
to use it if you'd like.
I had two main goals in my implementation:
- Keep it as close to "stan" JavaScript as possible
- Support multiple levels of inheritance
Its the first goal that distinguishes this implementation from others. In
Douglas' approach you have to use a specific API to define methods, while in
Joshua's and Dean's approaches you have to inherit from a base class and use
a specific API to define methods. For me Kevin's approach is the cleanest,
but I didn't come across it until after I had put together my own implementation.
Here is an example of how it looks (a quick aside - in this example I use
the old-school way of defining prototype methods to keep things simple. In
real-code, I generally use the Object.extend
idiom popularized by the Prototype library to add methods to an object - but
not to "" inheritance):
function Animal(name)
{
this.name = name
}
Animal.prototype.toString = function()
{
return "My name is " + this.name
}
function Pet(owner, name)
{
this.owner = owner
this.callInherited(arguments.callee, name)
}
Pet.inherits(Animal)
Pet.prototype.toString = function()
{
return this.callInherited(arguments.callee) + "\n" +
"My owner is " + this.owner
}
function Cat(owner, name)
{
this.callInherited(arguments.callee, owner, name)
}
Cat.inherits(Pet)
Cat.prototype.toString = function()
{
return this.callInherited(arguments.callee) + "\n" +
"I eat mice"
}
var cat = new Cat('charlie', 'oba')
alert(cat.toString())
The key things to notice are:
- The
inherits method is used to specify that one class inherits
from another class
- The
callInherited method is used to call the super class
- You can call up as many levels as needed - in this case
Cat.toString calls Pet.toString which
calls Animal.toString.
The thing I like least about the implementation is the need to pass arguments.callee
as the first parameter to callInherited. But before we can talk about why its
needed, we first need to look at the implementation.
Understanding JavaScript Inheritance
Since there is so much information on the Web about JavaScript inheritance,
I'll just refer you to the above links if you'd like to brush up on your knowledge.
But as a very quick reminder, the way to say a Pet inherits from an Animal
is like this:.
Pet.prototype = new Animal()
Pet.prototype.constructor = Pet
Note that we have to reset Pet's prototype's constructor to point back to
the Pet. This is an ugly wrinkle in JavaScript's inheritance and is needed
so that instances of Pets know that their constructor is Pet.
Using our example, let's draw this out:

The gray boxes with capital letters are constructors (JavaScript functions)
while the blue objects with underlined letters are instance of objects.
Let's start with the cat instance. It's constructor is the Cat function.
Cat's prototype is an instance of Pet, called pet.
Also notice that cat refers to its prototype, which is pet, through
a hidden pointer. In Mozilla this pointer is exposed via the __proto__ property.
It is not exposed in Internet Explorer. Thus, the best way to get the cat's
prototype is via this code:
cat.constructor.prototype
Because we had to reset pet's constructor to point to Cat, we can't
determine pet's real constructor, and thus can't determine its prototype.
The inherits method solves this by saving it in a property called prototype,
as show in the code below.
Function.prototype.inherits = function(parent)
{
this.prototype = new parent()
this.prototype.constructor = this
this.prototype.parent = parent
...
}
Implementing callInherited
Onto the tricky bit - how do we implement callInherited? Its
a two step process.
First, we need to determine the name of the method being currently executed
and what prototype contains it. Let's use Cat.toString as an example - its
defined as an anonymous function so it doesn't actually have a name. Thus the
need for the ugly callee parameter, which is pointer to the currently executing
method:
Cat.prototype.toString = function()
{
return this.callInherited(arguments.callee) + "\n" +
"I eat mice"
}
We can use this pointer to look up
the method name like this:
Function.prototype.inherits = function(parent)
{
...see above ...
this.prototype.callInherited = function()
{
var caller = arguments[0]
var args = new Array()
for (var i=1; i<arguments.length; i++)
args.push(arguments[i])
var currentConstructor = this.constructor
var methodName = null
while (methodName == null && currentConstructor != null)
{
methodName = figureMethodName(currentConstructor.prototype, caller)
currentConstructor = currentConstructor.prototype.parent
}}
...see below ...
}
function figureMethodName(object, method)
{
for (var key in object)
{
var value = object[key]
if (value === method) return key
}
return null
}
In Firefox and Internet Explorer we can don't have to specify callee as the
first parameter because the support the older, deprecated caller property (see
comments in the code). I'm not sure why caller was deprecated - its obviously
useful. But Opera, Konqueror and Safari don't support it.
Anyway, the algorithm is that we start at the current object and work our
way up the prototype chain until we find the calling method. Once we find it,
we know the method name and its containing prototype. So in our example, we
have found out that the calling method is named toString
and it is contained on the cat prototype.
The next step is to start at the containing prototype and
search its prototype chain for a method called toString.
while (method == null && currentConstructor != null)
{
method = currentConstructor.prototype[methodName]
currentConstructor = currentConstructor.prototype.parent
}
return method.apply(this, args)
In our example, we will start our search on the pet prototype looking for
a toString method. We find it and execute it.
Pet.toString in turn calls Animal.toString. So we go through
the whole process again. Starting at cat, we look for the calling method
as specified by caller. Eventually we find it on pet. Next, strarting
at animal, we look once again for a toString method and find it on animal.
What's Not to Like
As mentioned above, I find having to pass arguments.callee as the first paremter
to callInherited annoying. However, I haven't figured out a way around it (let
me know if you see one!).
More importantly, looking up the overriden methods is fairly slow. As a result,
there is additional code I haven't see to cache method lookups so they can
be reused.
So feel free to take a look at the code, and If you have any feedback I'd
love to hear it.
Update 1 - The original code used Prototype's $A function simply because I forgot to remove it - the code has now been updated.
Update 2 - I added a link to Joshua Gertzen's implementation.
Posted in JavaScript, JavaScript | 3 comments | 1 trackback
Posted by Charlie
Tue, 22 Aug 2006 05:27:00 GMT
This code has been deprecated - use the new and improved version instead.
I've always been a fan of JavaScript - its flexibility makes it
well tailored for its primary execution environment inside of web browsers.
It certainly counts as a language that gets
out of
your way.
As you probably know, JavaScript is based on prototypes.
What that means in practice is that you can change all existing instances of
an object at runtime, after they've been created, by adding or removing methods
from the object's prototype. You can also update a particular instance of an
object at runtime by manipulating just that object.
This capability is by no mean unique to JavaScript
- Ruby let's you do the same thing for example - but JavaScript is the most widely
deployed language that has this sort of flexibility. And I believe its the
only widely deployed prototype based language (anyone know of another that
is widely deployed?).
JavaScript Inheritance
Although JavaScript is fully object-oriented, its inheritance mechanism is
clunky. In fact, until the Ajax craze most people didn't even know that JavaScript
supported inheritance. Just look at the prototype library
- it defines an extend method that copies all the properties/method from one
object to another. Its a great example of JavaScript's flexibility, but not
a great example of software engineering.
The JavaScript 1.5 guide is
the place to learn how JavaScript's inheritance works. Its an updated version
of an old Netscape DevEdge article that
the Mozilla Foundation rescued from oblivion. I still
remember reading it back in 2000 - it was quite an eye opener - I hadn't realized
the power hiding within JavaScript.
Over the years a myriad of implementations have popped up to
simplify JavaScript inheritance. Some of the well known ones are from Douglas
Crockford, Kevin
Lindsey, Joshua Gertzen and Dean
Edwards. These are all fine implementations. They of course
differ somewhat in their capabilities and complexity.
My Take
A while back I put together my own implementation, but never published
it. Since my JavaScript posts seem to be pretty popular, I thought it was time
to open it up for review. Feel free
to use it if you'd like.
I had two main goals in my implementation:
- Keep it as close to "stan" JavaScript as possible
- Support multiple levels of inheritance
Its the first goal that distinguishes this implementation from others. In
Douglas' approach you have to use a specific API to define methods, while in
Joshua's and Dean's approaches you have to inherit from a base class and use
a specific API to define methods. For me Kevin's approach is the cleanest,
but I didn't come across it until after I had put together my own implementation.
Here is an example of how it looks (a quick aside - in this example I use
the old-school way of defining prototype methods to keep things simple. In
real-code, I generally use the Object.extend
idiom popularized by the Prototype library to add methods to an object - but
not to "" inheritance):
function Animal(name)
{
this.name = name
}
Animal.prototype.toString = function()
{
return "My name is " + this.name
}
function Pet(owner, name)
{
this.owner = owner
this.callInherited(arguments.callee, name)
}
Pet.inherits(Animal)
Pet.prototype.toString = function()
{
return this.callInherited(arguments.callee) + "\n" +
"My owner is " + this.owner
}
function Cat(owner, name)
{
this.callInherited(arguments.callee, owner, name)
}
Cat.inherits(Pet)
Cat.prototype.toString = function()
{
return this.callInherited(arguments.callee) + "\n" +
"I eat mice"
}
var cat = new Cat('charlie', 'oba')
alert(cat.toString())
The key things to notice are:
- The
inherits method is used to specify that one class inherits
from another class
- The
callInherited method is used to call the super class
- You can call up as many levels as needed - in this case
Cat.toString calls Pet.toString which
calls Animal.toString.
The thing I like least about the implementation is the need to pass arguments.callee
as the first parameter to callInherited. But before we can talk about why its
needed, we first need to look at the implementation.
Understanding JavaScript Inheritance
Since there is so much information on the Web about JavaScript inheritance,
I'll just refer you to the above links if you'd like to brush up on your knowledge.
But as a very quick reminder, the way to say a Pet inherits from an Animal
is like this:.
Pet.prototype = new Animal()
Pet.prototype.constructor = Pet
Note that we have to reset Pet's prototype's constructor to point back to
the Pet. This is an ugly wrinkle in JavaScript's inheritance and is needed
so that instances of Pets know that their constructor is Pet.
Using our example, let's draw this out:

The gray boxes with capital letters are constructors (JavaScript functions)
while the blue objects with underlined letters are instance of objects.
Let's start with the cat instance. It's constructor is the Cat function.
Cat's prototype is an instance of Pet, called pet.
Also notice that cat refers to its prototype, which is pet, through
a hidden pointer. In Mozilla this pointer is exposed via the __proto__ property.
It is not exposed in Internet Explorer. Thus, the best way to get the cat's
prototype is via this code:
cat.constructor.prototype
Because we had to reset pet's constructor to point to Cat, we can't
determine pet's real constructor, and thus can't determine its prototype.
The inherits method solves this by saving it in a property called prototype,
as show in the code below.
Function.prototype.inherits = function(parent)
{
this.prototype = new parent()
this.prototype.constructor = this
this.prototype.parent = parent
...
}
Implementing callInherited
Onto the tricky bit - how do we implement callInherited? Its
a two step process.
First, we need to determine the name of the method being currently executed
and what prototype contains it. Let's use Cat.toString as an example - its
defined as an anonymous function so it doesn't actually have a name. Thus the
need for the ugly callee parameter, which is pointer to the currently executing
method:
Cat.prototype.toString = function()
{
return this.callInherited(arguments.callee) + "\n" +
"I eat mice"
}
We can use this pointer to look up
the method name like this:
Function.prototype.inherits = function(parent)
{
...see above ...
this.prototype.callInherited = function()
{
var caller = arguments[0]
var args = new Array()
for (var i=1; i<arguments.length; i++)
args.push(arguments[i])
var currentConstructor = this.constructor
var methodName = null
while (methodName == null && currentConstructor != null)
{
methodName = figureMethodName(currentConstructor.prototype, caller)
currentConstructor = currentConstructor.prototype.parent
}}
...see below ...
}
function figureMethodName(object, method)
{
for (var key in object)
{
var value = object[key]
if (value === method) return key
}
return null
}
In Firefox and Internet Explorer we can don't have to specify callee as the
first parameter because the support the older, deprecated caller property (see
comments in the code). I'm not sure why caller was deprecated - its obviously
useful. But Opera, Konqueror and Safari don't support it.
Anyway, the algorithm is that we start at the current object and work our
way up the prototype chain until we find the calling method. Once we find it,
we know the method name and its containing prototype. So in our example, we
have found out that the calling method is named toString
and it is contained on the cat prototype.
The next step is to start at the containing prototype and
search its prototype chain for a method called toString.
while (method == null && currentConstructor != null)
{
method = currentConstructor.prototype[methodName]
currentConstructor = currentConstructor.prototype.parent
}
return method.apply(this, args)
In our example, we will start our search on the pet prototype looking for
a toString method. We find it and execute it.
Pet.toString in turn calls Animal.toString. So we go through
the whole process again. Starting at cat, we look for the calling method
as specified by caller. Eventually we find it on pet. Next, strarting
at animal, we look once again for a toString method and find it on animal.
What's Not to Like
As mentioned above, I find having to pass arguments.callee as the first paremter
to callInherited annoying. However, I haven't figured out a way around it (let
me know if you see one!).
More importantly, looking up the overriden methods is fairly slow. As a result,
there is additional code I haven't see to cache method lookups so they can
be reused.
So feel free to take a look at the code, and If you have any feedback I'd
love to hear it.
Update 1 - The original code used Prototype's $A function simply because I forgot to remove it - the code has now been updated.
Update 2 - I added a link to Joshua Gertzen's implementation.
Posted in JavaScript, JavaScript | 3 comments | 1 trackback
Posted by Charlie
Sat, 19 Aug 2006 20:10:00 GMT
If you write a lot of JavaScript, then you'll find Matthias Miller's website
chockfull of useful information. And even better, he's put together two great
tools.
The first is JavaScript
Lint, a tool that analyzes JavaScript code and reports potential
errors. Mozilla's SpiderMonkey JavaScript
engine has similar functionality, which you can turn on by typing about:config
as the URL and then searching for javascript.options.strict. However, JavaScript
Lint detects more types of errors and is configurable. To give it a try,
I ran it over the MapBuzz code base and was very impressed by the errors it revealed.
I immediately added it to our automated testing processes (i.e., its spawned
by a rake task
now) and have come to depend on it.
And if that wasn't enough, Matthias has adopted a second tool, called Drip,
that detects memory leaks in Internet Explorer's JavaScript engine. Memory
leaks occur in IE because it uses COM based
reference counting to delete objects. Reference counting is
fast, and easy to understand, but does not handle
circular object
references. As you use your website in IE, Drip keeps track of these circular
references. Once you're done, it prints out a report showing you where the
memory leaks occurred.
Thanks for the great tools Matthias.
Update1 - A few people have pointed out some negative articles aboout JSLint. I've never used JSLint so I don't have any opinions about it. What I'm talking about above is a totally separate project called JavaScript Lint (confusing, isn't it?). I highly recommend JavaScript Lint, it turned up a number of bugs that I hadn't caught previously. In addition, it is highly configurable so it's easy to turn off certains classes of errors. And for the utmost in flexibility, you can annote your code to tell JavaScript Lint to skip certain sections of it.
Update 2 - A couple of people mentioned FireBug and Venkman as invaluable tools. I couldn't agree more - I posted about Firebug a while back when I first started using it. And Venkman has been an old favorite for years - it was great to see it finally updated to workin Firefox 1.5. Hopefully it will also be quickly updated to work with Firefox 2.0. And if you're debugging Internet Explorer, Visual Studio provides a good JavaScript debugger as does Microsoft's free script debugger package.
Posted in JavaScript, JavaScript, Web, Web | 6 comments | no trackbacks
Posted by Charlie
Sat, 19 Aug 2006 20:10:00 GMT
If you write a lot of JavaScript, then you'll find Matthias Miller's website
chockfull of useful information. And even better, he's put together two great
tools.
The first is JavaScript
Lint, a tool that analyzes JavaScript code and reports potential
errors. Mozilla's SpiderMonkey JavaScript
engine has similar functionality, which you can turn on by typing about:config
as the URL and then searching for javascript.options.strict. However, JavaScript
Lint detects more types of errors and is configurable. To give it a try,
I ran it over the MapBuzz code base and was very impressed by the errors it revealed.
I immediately added it to our automated testing processes (i.e., its spawned
by a rake task
now) and have come to depend on it.
And if that wasn't enough, Matthias has adopted a second tool, called Drip,
that detects memory leaks in Internet Explorer's JavaScript engine. Memory
leaks occur in IE because it uses COM based
reference counting to delete objects. Reference counting is
fast, and easy to understand, but does not handle
circular object
references. As you use your website in IE, Drip keeps track of these circular
references. Once you're done, it prints out a report showing you where the
memory leaks occurred.
Thanks for the great tools Matthias.
Update1 - A few people have pointed out some negative articles aboout JSLint. I've never used JSLint so I don't have any opinions about it. What I'm talking about above is a totally separate project called JavaScript Lint (confusing, isn't it?). I highly recommend JavaScript Lint, it turned up a number of bugs that I hadn't caught previously. In addition, it is highly configurable so it's easy to turn off certains classes of errors. And for the utmost in flexibility, you can annote your code to tell JavaScript Lint to skip certain sections of it.
Update 2 - A couple of people mentioned FireBug and Venkman as invaluable tools. I couldn't agree more - I posted about Firebug a while back when I first started using it. And Venkman has been an old favorite for years - it was great to see it finally updated to workin Firefox 1.5. Hopefully it will also be quickly updated to work with Firefox 2.0. And if you're debugging Internet Explorer, Visual Studio provides a good JavaScript debugger as does Microsoft's free script debugger package.
Posted in JavaScript, JavaScript, Web, Web | 6 comments | no trackbacks