Recently in javascript Category

canto.js: An Improved HTML5 Canvas API

| 9 Comments

I love the <canvas> tag, but its 2D drawing API is intentionally minimal and unfriendly, so I've written a simple wrapper library that improves it.

canto.js defines a single canto() factory function. Pass a canvas element or the id of a canvas element to this function, and it returns a Canto object to you. This Canto object is a drawing context, like the one you'd get by calling getContext('2d') on the canvas element. The Canto object implements the 2D drawing API, so your existing canvas code should work as-is, but it also implements a number of other features.

One of the most important API improvements is that all Canto methods that do not have some other return value return the Canto object. This enables method chaining. For example:

// Draw a triangle
canto("canvas_id").moveTo(100,100).lineTo(200,200,100,200).closePath().stroke();

Notice that the lineTo() method in the code above has four arguments: this is an extension that allows the single method call to draw two line segments.

Another useful API extension is that methods that actually perform drawing operations (such as stroke(), drawImage(), fillText(), etc.) accept a set of graphics attributes to be used for that one operation.

// Draw a colorful triangle with wide lines
canto("canvas_id").moveTo(100,100).lineTo(200,200,100,200).closePath().
    stroke({lineWidth: 15, strokeStyle: "red"});

If you've used SVG you may be familar with the compact path descriptions syntax used in the d attribute of the <path> element. Canto supports this syntax, both with an svgpath() method and with individual single-letter methods like M (moveto), L (lineto), C (curveto) and so on. Here's the SVG version of our triangle:

// Parse an SVG path string
canto("canvas_id").svgpath("M100 100 L200 200 100 200 Z").fill();
// Define path elements with methods with really short SVG-inspired names
canto("canvas_id").M(100,100).L(200,200,100,200).Z().stroke();

Other new API features include relative-coordinate methods like rmoveTo() and rlineTo() and a turtle graphics API. A summary of the API is in the long comment at the top of the canto.js source code.

I've set up a canto-js project at code.google.com and have released it under the MIT license. Comments, bug-reports and contributions are all welcome. Test cases would be particularly nice. I've written a few simple tests myself, and I've run Canto against Phillip Taylor's suite of canvas tests. (Results: in Firefox and Chrome, at least, Canto passes effectively all the tests that the underlying un-canto'ed 2D context pass).

Note that Canto currently uses getters and setters to handle graphics attributes: if you set the lineWidth property on your Canto object, the setter method delegates to the underlying 2D context. IE doesn't support getters and setters, so Canto does not currently work in that browser.

Rough Cut of my JavaScript Book

| 1 Comment

O'Reilly has made a draft of the 6th edition of JavaScript: The Definitive Guide available through their Rough Cuts program. This means that you can buy online access (HTML and PDF) to the current draft of the book today, and then have the print version shipped to you when it is published, for the basic cover price of the book. (See the FAQ for more about how Rough Cuts works).

Online access is through Safari, not directly through O'Reilly, which means that you need to create an account with them in order to do this. But that's a minor hassle if you want the latest version right away.

Part I of the book is finished: complete coverage of ECMAScript 5, along with completely rewritten and modernized chapters on functions, objects and classes.

Part II is being updated for HTML 5 and is still in progress. The first few chapters have been pretty much completely rewritten but a number of chapters are still missing. The Rough Cuts edition will be updated each time I finish a new chapter. If you buy it now you get ongoing access to all the updates.

Quirks we can forget

| 1 Comment

I've just realized that there is one annoying JavaScript special-case that web developers no longer need to know about, and I don't need to document anymore.

As you know, JavaScript event handlers return false to cancel the browser's default action for the event. Except, that is, for the onmouseover event handler. Because of a bug in Netscape 2.0 (I think) we've always had to return true for that one. Documenting this special case has become a habit for me.

How nice, therefore, to realize that this is now irrelevant. The only default action associated with a mouseover event is to display the destination URL of a link. But to prevent phishing attacks, browsers no longer allow us to cancel this default action (and no longer allow any kind of status line scripting). Since the action can't be cancelled, the return value of onmouseover no longer matters. Hooray!

So I can now just document "return false to cancel". (Of course I still have to document e.preventDefault() for event handlers registered with addEventListener() and e.returnValue=false for event handlers registered with attachEvent(), but this is a step in the right direction.)

CSS opacity filter syntax for IE8

| 3 Comments

For a long time, IE's alternative to the CSS opacity property has been the filter property:

filter: alpha(opacity=50);

If you Google "IE8 opacity", you'll find a number of pages (including one at quirksmode.org) telling you that Microsoft removed support for opacity in a preview release of IE8, and then put it back in, but with a new syntax. These pages assert that in order to achieve the same half-transparent effect as above, you must write (note the -ms- prefix and the quoted value):

-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";

As far as I can tell, however, all of these pages are based on preview releases. My (very simple) testing indicates that the old syntax continues to work in IE8, and there is no need to add a second non-standard property to our stylesheets for IE8.

This post at the IE blog backs me up on this (scroll down to the section titled "A Pragmatic Solution") Or at least I think it backs me up. The post tries to explain and justify the initial change to the filter syntax but it just doesn't make much sense.

Someone please correct me if I'm wrong. Are there versions of IE8 in the wild that don't support the old filter syntax?

ECMAScript 5 Talk Tonight

| 3 Comments

I'll be speaking tonight in Vancouver, BC about the new features of ECMAScript 5.
Details here.

I'll post the slides after I give the talk.

Update: Here are the slides.

IE9 will have addEventListener, finally!

| 1 Comment

Microsoft has released a testdrive version of IE9 that includes support for:

  1. addEventListener()
  2. CSS3 Selectors
  3. CSS border-radius style for rounded corners
  4. SVG (no word on <canvas>, as far as I know, however)

Items 2, 3 & 4 are probably bigger news than item 1, but IE's lack of support for addEventListener() has always really irritated me. Finally, more than a decade after it was standardized, IE will support it. That means that by 2015 we can stop writing code that checks for addEventListener() and falls back on attachEvent().

A module loader with simple dependency management

| 4 Comments

I've written another version require2.js of my CommonJS module loader require() function. This one has two interesting features.

First, you can "pre-load" modules by mapping the module filename to the module function in the require._module_function object. If you do this, then the module will not need to be loaded. For example:

require._module_functions['math.js'] = function(require,exports,module) {
     // Code for the math module goes here
};

Second, this new version of require() has a require._print hook, which, if set to a suitable function, will print out the text of all modules it loads, wrapped in a function and assigned to the require._module_function map as above. You can even define a require._minimize hook if you want to do code minimization on your modules.

I've defined another script display_requirements.js that defines suitable _print and _minimize functions.

So, here's the upshot. For relatively simple applications that load modules statically at start up, use the require2.js script for loading modules. Its inefficient, but works well during the development phase. Then, when you're getting ready to deploy your application, load the display_requirements.js script after loading require2.js but before you actually call require() anywhere. This will cause a big chunk of code to appear at the bottom of your web page--pre-loaded minimized versions of all the modules you used. Cut-and-paste this code into a new file named requirements.js (or even paste it at the bottom of require2.js) and load the requirements.js script in place of the display_requirements.js script. Now you can continue to use require() as you have always done, but it won't have to hit the network to load your modules.

I haven't done much deployment of real-world web applications, and am not qualified to say whether a system like this would actually be helpful in practice. But it was an easy tweak to my existing code, so there it is.

CommonJS Modules implementation

| 11 Comments

I've implemented the CommonJS Modules 1.0 specification with the code in this file. It appears to pass the compliance tests when run in Firefox and Chrome on Linux, and also when run standalone in Tracemonkey, Rhino or V8.

Note that this implementation does not use the namespace probing technique I described in my previous post.

Update: One of the things that really surprised me when testing my implementation was to discover that the CommonJS spec requires (this is not explicit in the specification text, but it is explicit in the conformance tests) the require() function to return the actual exports object of a module, and not make a defensive copy of it.

Suppose a program includes module A which includes modules B and C. Module C can require B and then add, replace, or remove methods from B's API. Later, when the program includes Module B directly, it will get the modified version of B. In order to correctly use this modified module B, the programmer will have to read the documentation for module C!

Update 2: There are great comments to this post, including a link to Luke Smith's blog post that argues that the synchronous nature of CommonJS modules is not a good fit for client-side scripting. In response I wanted to make clear that I posted this code because I thought it was interesting, not because I think that client-side programmers should go out and start using it right away.

Functions as Namespaces, and How to Peek Inside

| 19 Comments

It has become common in modern JavaScript programming to use functions as namespaces. If you put your code inside a function, then your variables and functions are local to the containing function and do not clutter up the global scope.

var value = (function() {  // Wrapper function creates a local scope or namespace
    // your code goes here
    return value;  // Export a value from the namespace
)());  // Invoke the wrapper function to run your code      

Now suppose that you have some JavaScript code as a string--you've just loaded it using XMLHttpRequest, for example. You're going to evaluate the code, and you might want to evaluate it in a namespace so that it doesn't define functions and variables in the global scope. This is easy: just wrap it in a function before evaluating it. In this case, the Function() constructor is even more handy than the eval() function:

var code = ....;  // A string of JS code to evaluate
var f = new Function(code);   // Wrap it in a function
f();    // And run the function

The problem with doing this is that the function creates a sealed namespace and we can't see what is inside. If the code defines something useful like a function or a class, we can't access it, and it does us no good.

Here's a trick I've just discovered. (I'm sure someone else has thought of this, but I haven't seen it used or described elsewhere). Before you wrap your code in a function add this line to it:

return function(s) { return eval(s); };

Now, when you invoke the wrapper function, it returns this evaluator function to you. The returned function evaluates a string in the scope of the namespace, so you can use it to peek into the namespace and extract whatever values you want!

If your string of code defines a constructor function named Set() that you want to use, you can run the code in a namespace and then extract f from the namespace like this:

var code = readFile("Set.js");  // A string of JS code to evaluate
// Define and invoke a wrapper function with special suffix code.
// The return value is a namespace evaluator function and we treat
// it as a namespace object.
var setns = new Function(code + "return function(s) { return eval(s); };")(); 
var Set = setns("Set");  // Import the Set function from the namespace.
var s = new Set();  // Use the class we just imported

And what if there are 3 values you want to extract from the namespace?

// Extract an object containing 3 values from the namespace
var sets = setns('{Set:"Set", BitSet:"BitSet", MultiSet:"MultiSet"}');
var bs = new sets.BitSet();

I've defined a namespace() function for loading code and doing this kind of namespacing automatically:

Google Closure Library and Optimizer

| No Comments

Google has open-sourced the javascript library and optimizer they use in gmail and other web applications. They call it "Closure" and you can read about it here.

While the optimizer looks very cool, I think the library is most impressive. Its a really large code base, and at least some of it has been thoroughly field-tested in gmail and similar applications. You can get the code like this:

svn checkout http://closure-library.googlecode.com/svn/trunk/ closure-library-read-only

The closure library is intended to be used with the closure optimizer which removes unused code, so the APIs are broad with lots of methods--there is no sense that the closure developers were skimping on API in order to pack everything into a small download bundle. Also, and perhaps for the same reason, the code is not full of micro-optimizations. Compared to the jQuery and YUI code (for example) the Closure code is straightforward and easy to understand.

Function objects in JavaScript are callable: you can invoke them. Other, non-function objects are allowed to be callable, however. Host objects in IE (things like Window.alert()) are callable, but are not native function objects. (Other browsers implement DOM methods as true native function objects). Also, a number of browsers have followed Firefox's lead in making RegExp objects callable even though they are not functions. Although you can invoke any callable object like a function, the difference is that callable objects don't have function methods call() and apply() (and bind() in ECMAScript 5).

Today, the typeof operator returns "function" for true function objects, and returns "object" for IE's callable host objects. Most browsers return "object" for callable RegExps, but Safari returns "function", and Google Chrome is likely to follow Safari's lead on this. If you want to be sure that something is a true function (and not a regexp) you can use something like this:

function isFunction(x) { 
    return Object.prototype.toString.call(x) === "[object Function]";
}

There is not today a reliable way to write an isCallable() function, however.

Things change in the ECMAScript 5 specification. The typeof operator is required to return "function" for any native or host object that is callable. When IE implements the spec, we can expect "typeof window.alert" to evaluate to "function". The problem is that browsers like Firefox and Opera that have callable regexps are unlikely to implement the spec: the typeof operator on a regular expression will continue to return "object" for those browsers. The committee writing the specification was aware of this problem, but ran out of time to fix it.

So today typeof x === "function" is close to an isFunction() test, but it fails for regular expressions in some browsers. In ECMAScript 5, typeof will be close to an isCallable() test, but it will fail for regular expressions in some other browsers.

Fortunately, the isFunction() test above should continue to work in ECMAScript 5, and
there is a way to write a reliable isCallable() function in ECMAScript 5. It relies on the fact that the Array.prototype.forEach() method checks its argument for callability even when invoked on an empty array. (So this isCallable() function assumes that browser vendors implement the Array.forEach() method as specified.) Here it is:

Object.isCallable = function(o) {
    // Array.prototype.forEach throws TypeError for non-callable arguments
    try {
        [].forEach(o);  // o will never be invoked, but it will be tested for callabilty
        return true;
    } catch (x) {
        if (x instanceof TypeError) return false;
        else throw x;
    }
};

I was recently writing some documentation for the Array.forEach() method (part of ES5, but most browsers other than IE support it now) and worrying about the fact that there is no clean way to terminate the iteration prematurely. Nothing like the break statement, that is. If you really want to get out of the loop, the function you pass to forEach() has to throw something. And the forEach() method won't catch it for you, so you've got to write your own try block.

Then, when working with the new array predicate method Array.some(), I realized that we don't have to think of it as a predicate method. If we ignore the return value, it is an iterator method that works just like Array.forEach() except that if your function returns true (or any truthy value) then the loop terminates. So inside of the function you pass, a plain return statement with no value is like using a continue statement. And "return true" is like a break statement, causing the loop to terminate. The implicit return that occurs at the end of the function body returns undefined, which is like returning false--it keeps the loop going.

The Array.every() method is not so useful this way: you have to explicitly return a truthy value to keep the loop going, so an implicit return at the end of the function body would act like a break statement.

The problem I see with using some() in this way is a stylistic one: the name really doesn't look like the name of an iterator the way that "each" and "every" do.

Good algorithms are better than clever code

| 5 Comments

Yesterday, I posted an entry about a clever way to implement string multiplication in JavaScript using Array.prototype.join()

In comments, redraiment challenged me, suggesting that an implementation based on string doubling would be more efficient. Sure, I thought, for really large values of n, but surely for small n, using the native join() method would be better, wouldn't it?

It turns out that writing a good algorithm is better than being overly clever (at least in these days of really good JIT interpreters). Here's my new string multiplication code:

String.prototype.times = function(n) {
    var s = this, total = "";
    while(n > 0) {
	if (n % 2 == 1) total += s;
	if (n == 1) break;
	s += s;
	n = n>>1;
    }
    return total;
};

By my simple benchmarks, this implementation is significantly faster than using join(), even when only multiplying by 1 or 2. I've tested it in Firefox 3.5, IE 8 and Safari 3.

String Multiplication in JavaScript

| 13 Comments

In Ruby, the "*" operator used with a string on the left and a number on the right does string repetition. "Ruby"*2 evaluates to "RubyRuby", for example. This is only occasionally useful (when creating lines of hyphens for ASCII tables, for example) but it seems kind of neat. And it sure beats having to write a loop and concatenate n copies of a string one at a time--that just seems really inefficient.

I just realized that there is a clever way to implement string multiplication in JavaScript:

String.prototype.times = function(n) {
    return Array.prototype.join.call({length:n+1}, this);
};

"js".times(5) // => "jsjsjsjsjs"

This method takes advantage of the behavior of the Array.join() method for arrays that have undefined elements. But it doesn't even bother creating an array with n+1 undefined elements. It fakes it out using and object with a length property and relies on the fact that Array.prototype.join() is defined generically. Because this object isn't an array, we can't invoke join() directly, but have to go through the prototype and use call(). Here's a simpler version that might be just as efficient:

String.prototype.times = function(n) { return (new Array(n+1)).join(this);};

When you call the Array() constructor with a single numeric argument, it just sets the length of the returned array, and doesn't actually create any elements for the array.

I've only tested these in Firefox. I'm assuming that either is more efficient than anything that involves an actual loop, but I haven't run any benchmarks.

Proposed coding convention for closures

| 6 Comments

By now, many of us have gotten used to using closures in JavaScript to define a scope that holds private variables and utility functions so that we don't have to put these in the global namespace. The idiomatic code looks like this:

(function() {
      var private_var;    // Visible only inside this function
      function helper_function() { ... }
      
      // export an object or function to the global namespace
})();  // Invoke the outer function

The outer function exists only to create a scope to hold our internal variables. It has no name and is invoked exactly once, immediately after being defined. The fact that this is a function expression (rather than a statement-like function declaration) means that we can invoke it immediately after defining it. The parentheses before the function keyword and after the closing } are required because otherwise the JavaScript interpreter would think that this was a function declaration and would complain about the missing function name.

That unusual opening parenthesis before "function" serves another important purpose in this idiom. It alerts us to the fact that this function is being used idiomatically, that it exists solely to create a scope and that it is going to be invoked immediately.

So far, so good. But I've finally gotten around to reading Douglas Crockford's JavaScript: The Good Parts and it has made me think that an additional explicit naming convention would be helpful. (As an aside, Crockford's short book is worth a read, though I find that I disagree with some of his coding conventions. I'm tempted to write a review titled "JavaScript: The Good Parts: The Good Parts"...)

When the function keyword is the first token in a new JavaScript statement, the interpreter expects to see a function declaration, not a function expression. That's why we needed the idiomatic parentheses in the code above. But when the function keyword is used as part of an assignment or as an argument to some other function, those parentheses are not required. Crockford's book includes code like this (page 37):

var myObject = function() {
    var value = 0;

    return { // 7 lines of code omitted here
    };
}();

When I first read the assignment statement it appears to me (despite the name of the variable) that it is a function value being assigned. In fact, however, the function is merely there to establish a scope for private variables. The function is invoked as soon as it is defined, and it is the return value of the function that is assigned. The problem is that I don't realize this until I read all the way down to the end of the function. Appendix E takes this to an extreme. The code begins:

var json_parse = function() {

It looks like we're creating a function and assigning it to the variable json_parse. But five pages later we see:

}();

Now we realize that the value assigned to json_parse is not the function we thought it was, but the function returned by that function.

Another example appears on page 40:

String.method('deentityify', function() {
   // 25 lines omitted
}());

It appears at first that we're passing a function as the second argument of the invocation of String.method. It is not 'till we read all the way through this function that we realize that we're passing the result of invoking the function.

So, how can this code be improved? One way would be to use the idiomatic parentheses around function expressions that are going to be immediately invoked even when they are not necessary. That would turn the code above into this:

String.method('deentityify', (function() {
   // 25 lines omitted
})());

I think that would be helpful, but I think we can do better. Function expressions are allowed to have names, and those names are only visible within the body of the function (allowing such a function to invoke itself recursively, for example). So let's say that when we're going to define a function for the purpose of creating a scope we make that explicit by giving it a dummy name like "scope" or "closure" or "invocation". This results in code like:

var myObject = function scope() {
   // code omitted
}();

String.method('deentityify', function invocation() {
   // 25 lines omitted
}());

Your thoughts are welcome in the comments. Has anyone else proposed a convention like this? What's the best name to use for these functions?

Update: I suppose we could also simply adopt a comment-based convention:

var myObject = /* return value of */ function () {
   // code omitted
}();

String.method('deentityify', /* result of */ function() {
   // 25 lines omitted
}());

Update 2: It turns out that Douglas Crockford is about 2 months ahead of me. In March he updated jslint to (optionally) issue warnings about immediate invocation of function expressions unless the entire invocation appears in parentheses, and also to warn if a function is parenthesized and is not immediately invoked. So Crockford's convention looks like the following:

var myObject = (function () {
   // code omitted
}());

String.method('deentityify', (function() {
   // 25 lines omitted
}()));

Note that Crockford wraps the invocation in parens, not just the function. That is, he uses ()) at the end instead of (the more commonly used) )(). He has said that he'll update his book to follow these conventions in the next printing.

New ECMAScript version numbering scheme

Per a post today on the es-discuss mailing list, the next version of the JavaScript standard will be ECMAScript 5. This version was previously called ECMAScript 3.1, and is a relatively small and long-overdue update to the language. Version 4 of the standard has been in the planning stages for 10 years or more, but those plans have been scrapped. To avoid confusion, with those old plans, however, there will be no version 4 of the standard.

Method Chaining Part 2

The comments on my last post about method chaining in JavaScript were spectacular, and I want to publicly thank all who took the time to read my code and think about it. The final version of the code (which you can see below the fold) is much stronger thanks to their comments.

In the 5th edition of my JavaScript book I made the embarrassing mistake of recommending a constructor and method chaining technique that only works for shallow class hierarchies--it works when class B extends A, for example, but not when C extends B and B extends A.

The technique I recommended was to put a superclass property in the prototype object of a class, and then to chain to a superclass constructor by calling this.superclass(). To see why this fails, imagine that we're creating an instance of class C (which extends B which extends A). The constructor C() chains to B() by calling this.superclass(). The constructor method B() is invoked on the same instance of C, however, so when it attempts to chain to A() by calling this.superclass(), it just ends up invoking itself. This incorrect chaining technique is discussed in sections 9.5.1 and 9.5.2, and is also used in example 9-10 and 9-11 at the very end of the chapter. I blogged about this mistake and a possible workaround almost two years ago.

Now, however, O'Reilly is preparing to do a reprint of the book, and I have an opportunity to fix this mistake. Below is a revised code from examples 9-10 and 9-11. I've renamed the defineClass() method to Class() and have modified it so that it automatically does constructor chaining (I was inspired by dojo for this change). More importantly, I've simplified method chaining by defining a global method named chain() for method chaining. If a method overrides a method defined by a superclass (or a "mixin" class) it can invoke that overridden class by invoking chain() like this: chain(this,arguments). (The second argument must be the arguments array of the overriding method, and the first argument must be the object on which that method was invoked.)

The code is below the fold. I think this is interesting JavaScript, and I'd love to have it checked for errors before it goes into print again... Please leave a comment if you think it could be improved! Update: comments are now closed; spammers have struck.

Dashed lines in the <canvas> tag

| 1 Comment

The <canvas> tag supports all of the normal line attributes (width, join style, cap style, miter limit) except for dashes. Given that Apple's original implementation of <canvas> seemed a little bit rushed, I have always assumed that this was a simple oversight, and that it would soon be corrected in newer implementations.

I did, however, submit a comment about it to WHAT-WG. I was quite surprised to find out that they have no intention of supporting dashed lines. I've argued and argued with Ian Hickson about this, but he is unmoved. Supporting dashed lines would be non-trivial, he believes, and there haven't been enough requests for them.

So, this post is a public service announcement. If you were assuming, as I did, that dashed lines would be supported by the official specification of the <canvas> tag, you should be aware that they will not be. If, like me, you think that it is a mistake to define a graphics library that cannot natively draw dashed lines, then you can submit a comment to that effect to whatwg@whatwg.org.

More on IE and window.event

| 6 Comments

Julien Royer sent me an email today following up on this post. Try the following code in IE:

<script>
window.onload = function() {
  alert(window.event == window.event)
}
</script>

When I run this in IE6 on a Windows XP machine, I get false. This is just weird. The window.event object thinks that it is not equal to itself.

This probably does not have any impact on real-world code. I bring it up, however, because in that last post about IE and events, my commenters and I decided that the event object passed to an event handler registered with attachEvent is not the same as window.event. The code shown here calls that into question. Perhaps they are the same objects, but the weird behavior of window.event causes them to appear unequal.

In the 5th edition of my book, I propose a convention for constructor chaining:

  • When you define a class B as a subclass of A, set B.prototype.superclass=A
  • Then, in the constructor B(), you can chain to the superclass constructor with the natural syntax this.superclass()

Reader Bruce Wallace has just pointed out a serious flaw in this approach: you can only use it once. If you use this trick twice in the same inheritance hierarchy, you end up with infinite recursion. (If you don't see why, you can try to work out an example that includes C as a subclass of B. Or just forget it, since I think I have a better approach below.)

I'm feeling pretty embarassed to have suggested this defective method of chaining, and to have committed my suggestion to print! However, I hope to make up for it by proposing a better alternative. Here is my new convention:

  • First, define the following function:
    function super(o, args) {
        if (args.callee.superclass)
    	return args.callee.superclass.apply(o, args);
    }
    
  • For each constructor B that subclasses A, set B.superclass=A;
  • Do the same thing if a method of B overrides a method of A. For example:
    B.prototype.toString.superclass = A.prototype.toString;
    
  • In the B() constructor, chain to your superclass constructor like this:
    super(this, arguments)
    
  • And in a method like B.toString(), chain to A.toString() with exactly the same syntax.

This works because arguments.callee is the function that is currently running. Note that this chaining convention passes all the arguments of the subclass constructor or method to the superclass constructor or method, even if some of them are unused. So it won't work if a subclass constructor expects its arguments in a different order than the superclass constructor.

Note that the work of setting the superclass property on constructors and methods can be done by a suitable class definition utility method (such as example 9-10) in my book. This means that when writing your constructors and methods, you don't have to worry about linking the chain together; you can just call the super() method whenever you want to.

Anyone see any flaws in this approach? Comments? Suggestions? There is a simple test case defining a class hierarchy C extends B extends A below, but I haven't tried to test this extensively yet, and I''ve only run it in Firefox. Firefox is letting me use the function name "super" even though that is one of the identifiers that is unused but nominally reserved by ECMAScript v3. I choose super because Java uses that, but "chain" would probably be a safer choice.

Here is my test code:

// Magic constructor and method chaining function
function super(o, args) {
    if (args.callee.superclass)
	return args.callee.superclass.apply(o, args);
}

// Class A
function A(a) { this.a = a; }
A.prototype.toString = function() { return this.a + "" };

// Subclass B
function B(a, b) {
    super(this, arguments);
    this.b = b;
};
B.superclass = A;
B.prototype = new A();
B.prototype.toString = function() {
    return super(this, arguments) + this.b;
};
B.prototype.toString.superclass = A.prototype.toString;

// Sub-subclass C
function C(a,b,c) {
    super(this, arguments);
    this.c = c;
}
C.superclass = B;
C.prototype = new B();
C.prototype.toString = function() {
    return super(this, arguments) + this.c;
}
C.prototype.toString.superclass = B.prototype.toString;

// Create an instance of C and call toString() should display "123"
var c = new C(1, 2, 3)
alert(c.toString());

Nifty DOM output stream class

| 7 Comments

I was porting some JavaScript code that used the TrimPath template library. The templating system was too much for my needs, so I came up with the simple little class below. It simulates a Java-style output stream. Pass the id of a DOM element to the constructor to get started. Call the clear() method first, if necessary. Then call the write() method as many times as needed. Finally, always remember to call flush() to force your output to appear.

// A little class for outputting HTML into a DOM element
function DOMStream(id) {
    this.elt = document.getElementById(id);
    this.buffer = [];
}
DOMStream.prototype.clear = function() { this.elt.innerHTML = ""; };
DOMStream.prototype.write = function() {
    for(var i = 0; i < arguments.length; i++) this.buffer.push(arguments[i]);
};
DOMStream.prototype.flush = function() {
    this.elt.innerHTML += this.buffer.join("");
    this.buffer.length = 0;
};

If it is not obvious, an important point of this class it to avoid inefficient repeated string concatenation. This is why it uses an array as a buffer, and why the write() method accepts multiple arguments--so you don't have to concatenate them yourself.

Here's a sample usage:

var out = new DOMStream("placeholder");
out.write('<h2>', section_title, '</h2>');
outputTable(out, data);  // Function defined elsewhere
out.flush();

With this class defined, I ported the trimpath template to equivalent JavaScript functions, and ended up with a modest reduction in the number of lines of code (not counting the substantial reduction in lines of code I got by no longer using the templating library.)

Notable New JavaScript Books

The 5th edition of my book was not the only notable JavaScript book released this summer. I'd like to draw your attention to these two as well:

The authors of these two books, Christian Heilmann and Peter-Paul Koch, were kind enough to serve as technical reviewers on my book, and were also kind enough to send me copies of their own books.

I cannot actually review their books, however, since I have not had the time to read them. Nevertheless, the author's reputations speak well for the books. Both Christian and Peter-Paul are active web developers, members of the DOM Scripting Task Force (of the Web Standards Project) and advocates for unobtrusive scripting, accessibility, and other modern scripting practices.

Neither of these books aims to be "definitive" in the way mine does, but both are written by authors who have a lot of valuable experience with todays best practices. Since I haven't read the books myself, I can't tell you whether they share that experience effectively in these books. But I hold the authors in high esteem and want others to be aware of their work.

Rhino cover in Weird Al Music Video

| 1 Comment

Musician Weird Al Yankovic has released a music video for his song "White and Nerdy". The cover of my JavaScript book appears in it. (I can't tell if its the fifth edition, though.)

You can find the video at the musician's MySpace site, and also by searching YouTube.

The JavaScript reference is 1 minute 14 seconds into the video.

What's New in the 5th Edition

| 2 Comments

At another blog I saw someone comment that they'd been looking for a list of what is new in the 5th edition of JavaScript: The Definitive Guide. I guess I haven't blogged about this yet. If you were looking at the book in a bookstore, you'd just turn to the Preface and read the section titled "What's New in the Fifth Edition". But if you're considering an online purchase, you can't do that. So, here's what I say about the new edition in the preface:

Book Metrics: 1 kilopage

| 3 Comments

In yesterday's post, I promised to stop plugging my new book. But I've got a copy in my hands now, and I just can't stop myself. This post will contain only trivia, without links or exhortations to BUY IT NOW!

The first thing I noticed about 5th edition is that it is thinner than the 4th edition. Apparently it is printed on thinner (also noticeably whiter) paper than the 4th edition. Rest assured, however, that this new edition is longer (and better) than the old. The 5th edition is 10% longer (in page count). It has 92% more examples (125 examples instead of 65) and the new examples are 169% longer (lines of code) than the old ones.

But here's my favorite fact about the 5th edition: if you count the regular numbered pages, the roman-numeral preface pages, and the unnumbered filler pages at the back, the book is exactly 1024 pages long. One kilopage: I couldn't be prouder!

The 5th edition of my JavaScript book is finally shipping! (From amazon.com, anyway. Amazon.ca and amazon.co.uk don't seem to have it yet.) Interested?

  1. Read a sample chapter.
  2. Study the examples.
  3. Order it from Amazon: see the ad in the left column.

I think this is the last time I'll plug my book on this blog!

Sample Chapter: JavaScript and XML

| 3 Comments

O'Reilly has posted a PDF file of Chapter 21, JavaScript and XML, from my book

This chapter shows you how create, load, parse, serialize, transform and search XML documents using JavaScript. It includes a portable HTML templating system like IE's data island stuff.

Examples for this chapter, and all chapters of the book are also available.

I'm told that the book will be in bookstores by the end of the month. And you can pre-order it from Amazon today:

JavaScript Examples

| 5 Comments

My JavaScript book has been sent to the printer! I'm told it should be in bookstores by the end of the month. You can always pre-order it, though:

Meanwhile, you can get your hands on the examples from the book now.

10 Years of JavaScript

| 1 Comment

I just had the chance to review the copyright page of the 5th edition of my JavaScript book and noticed that its publication date (August, 2006) is exactly 10 years after the August, 1996 publication date of the first, "beta" edition of the book.

Thus inspired, I put together the following timeline of the JavaScript language, the client-side DOM, and of JavaScript: The Definitive Guide. I'm sure it is incomplete: additions in the comments are very welcome.

1996 March

JavaScript 1.0 released in Netscape 2.
document.write() and form manipulation are possible

1996 August

JavaScript: The Definitive Guide beta edition

1996 August

JavaScript 1.1 released in Netscape 3.
Adds array support to the core language.
Image rollovers become possible.

1996 August

IE 3 released: JScript 1.0/2.0

1997 January

JavaScript: The Definitive Guide second edition

1997 June

ECMAScript v1 standardized

1997 June

JavaScript 1.2 released in Netscape 4.
Adds switch and regexps to the language.
<layer> tag supports rudimentary DHTML

1997 October

IE 4 released: JScript 3.0
DOM based on document.all[] allows DHTML

1998 June

JavaScript: The Definitive Guide third edition

1998 June

ECMAScript v2 standardized (minor corrections only)

1998 October

JavaScript 1.3 released in Netscape 4.5.
Compliant with ECMAScript v1

1998 October

W3C publishes DOM Level 1 standard

1999 March

IE 5 released: JScript 5.0

1999 December

ECMAScript v3 standardized

2000 July

IE 5.5 released: JScript 5.5
partial support for W3C DOM

2000 November

JavaScript 1.5 released in Netscape 6.
Compliant with ECMAScript v3
Basic support for DOM, <layer> tag abandoned

2000 November

W3C publishes DOM Level 2 standard

2001 October

IE 6.0 released: JScript 5.5
substantial support for W3C DOM, except Events module

2002 January

JavaScript: The Definitive Guide fourth edition

2002 June

Mozilla 1.0 released

2004 November

Firefox 1.0 released

2005 February

Jesse James Garrett coins the term Ajax

2005 July

DOM Scripting Task Force forms,
publishes The JavaScript Manifesto

2006 August

JavaScript: The Definitive Guide fifth edition

Two final notes. First, Amazon is still saying that they'll be shipping copies of the book around August 1st. I can say for sure that the book won't be ready by the beginning of August. I don't actually know much about the printing process, but it seems reasonable to suppose that the book will be available later in August.

Second, I've lost my only copy of the 10-year old Beta edition of my book. If you have a copy, in reasonable condition, with the word "BETA" stamped across the rhino, and are would like to swap it for a brand-new copy (signed, if you want) of the 5th edition, send me an e-mail and we'll arrange a trade.

Update: comments closed. Comment spammers have discovered this entry.

Jitsu: new framework for web apps

| 3 Comments

Jitsu is a new web application framework. They call themselves "a next-generation user interface toolkit for building rich web applications"

Jitsu was developed by ATTAP, but has been open-sourced. The website is slick, and there is a well-written tutorial. Its a complete application framework, not something you can just add onto an application, so you really have to adopt it from the start. But its got a lot of nice features, and particularly strong bi-directional data-binding capabilities.

I haven't actually used it myself, but it looks very promising.

New Edition of my JavaScript Book!

| 5 Comments

At long last, the 5th edition of JavaScript: The Definitive Guide is complete! Amazon is accepting pre-orders, and O'Reilly should be releasing a sample chapter soon.

I'm pleased with how this edition came out. In Part I, which covers the core language, the material on functions, closures, and classes has been strengthened, and there are new chapters on namespaces and on embedding JavaScript in Java 6 programs.

The biggest changes are in Part II of the book, which covers client-side JavaScript. Two new chapters on scripted HTTP and XML processing cover Ajax. Another new chapter on scripted client-side graphics covers the <canvas> tag, SVG, and alternatives. The chapter on cookies has been extended to discuss other client-side persistance mechanisms. And the chapter on scripting Java applets has been extended to also cover scripting Flash movies.

All these changes should bring the book up-to-date for "Web 2.0"

When are document elements available to scripts?

| 9 Comments

As far as I can tell, the DOM and HTML specifications are silient on the issue of when DOM elements become available to scripts embedded within the document. That is, if you have an element <div id="foo">, when can you call getElementById('foo') and be sure that you'll get a valid result?

To be safe, we typically wait for the onload() event. (Although the specifications don't explicitly guarantee that, either.) It appears to be common practice for browser vendors to make the DOM available while it is being parsed. That is, any script in the body of a document can access any elements that appear before it in the document.

Can anyone with more knowledge of the specifications, or with more experience writing production code comment on this issue?

This is, of course, related to the "onload problem" which Dean Edwards purports to have solved. In the comments to that post, Dean asserts that placing scripts at the very end of the body does not guarantee that those scripts will have access to the whole document. Dean's experience carries a lot of weight, but he does actually have code that demonstrates that this technique is unreliable.)

Comments are open.

Flash Persistence: one more try

| 4 Comments

[Update: this may be a false alarm. See how I resolved the problem.]

I'm still trying to find a workaround to the Flash persistence security hole that opens up when you script your flash movies from JavaScript.

What I want to try now is to code my ActionScript so that it compares the URL of the Flash movie of which it is a part (something like _root.movieClip._url) to the URL of the web page in which the movie is embedded. If they are not the same, then the actionscript knows that it is being hotlinked, and can refuse to return any persistent data.

My problem is that I don't know the ActionScript programming environment or API well, and I can't find a way to find the URL of the document in which the movie is embedded. It seems like there ought to be a way, but I don't know...

Anyone know how to do it?

More on the Flash Persistence Security Hole

| 5 Comments

[Update: this may be a false alarm. See how I resolved the problem.]

I've been looking for a way to work around the security hole in the flash persistence mechanism that I described in the previous post.

Since the hole occurs when one site hotlinks a Flash movie on another site, it seemed to me that the obvious solution would be to prevent hotlinking. So I set up a .htaccess file using the Apache mod_rewrite module and the HTTP_REFERER header. It worked: offsite links to the SWF file were prevented.

But this wasn't good enough. I didn't take caching into account. Suppose user has just visisted Site A, and that site uses a scriptable Flash movie to store persistent data locally. The user then visits Site B, which is the malicious one. Site B hotlnks the movie on Site A and scripts it to gain read access to the persistent data. My .htaccess file on the server was supposed to prevent this kind of hotlinking. But the server never gets involved: Site B doesn't need to ask the Site A server to send it the movie: the movie is already in the browser's cache, and Site B can read Site A's persistent data with no trouble.

Anyone have a solution to this problem? I'm ready to give up and declare that Flash-based persistence is only good as a cache for information that is already publically available on the network.

And as a meandering aside, let me say that there are some interesting uses of it there. I gather that XMLHttpRequest bypasses the browser cache, at least in certain browsers. Flash persistence could be used to create a persistent cache for XMLHttpRequest. This might be useful for a web site that had a bunch of pages that all did XSLT using the same stylesheet, which was retrieved with XMLHttpRequest.

Adam Vandenberg has an XMLHttpRequest caching solution but the cache only persists for the lifetime of the current page. Flash persistence might be an interesting addition to his caching code. (Of course, we'd have to confirm that this Flash security hole only gives read access to the cached data; otherwise any website could corrupt the Flash cache of any other.)

Security Flaw in Flash-based Persistence

| 4 Comments

[Update: this may be a false alarm. See how I resolved the problem.]

Inspired by Brad Neuberg's AMASS project, I've been experimenting with using the Flash plugin as a client-side persistence mechanism, as an alternative to cookies. It allows the storage of much more data, and that data doesn't have to be uploaded to the server for every webpage that uses it. This seems important, and projects like AMASS seem like they have breakthrough potential.

However, I've discovered something I'm worried about. Persistence in Flash is done with the SharedObject class. By default persistent data is not shared among Flash movies: it is only accessible to the movie that stored it. SharedObject has a way to loosen this up, like the path attribute of a cookie. You can specify that all Flash movies in the same directory can share persistent data, for example. Or you can specify that all Flash movies from the same website can share data.

This may be fine when the data is locked inside the Flash movies. But when Flash movies are scriptable, we run into problems. Both AMASS and my own experiments with Flash-based persistence use a simple invisible movie to make the necessary calls to the SharedObject. Both script the Flash plugin with JavaScript so that we can persist client-side JavaScript data.

And this is where the problems arise. Flash governs access to the data based on the URL of the movie; it doesn't seem to care about the URL of the document within which the movie is embedded. Suppose, therefore, that Site A uses a scriptable Flash movie to persistently store some data from JavaScript. Site B can hotlink that scriptable movie right off of Site A, and the JavaScript code on Site B can read the data stored by the JavaScript code on Site A. (In my experiments, Site B cannot overwrite or delete the data stored by Site A, but it can read it.)

My testing was done using Firefox 1.0.6 using the Linux version of the Flash player 7.0 r25.

Update:I have now obtained the same results using Firefox 1.02 and Flash version 8 on a Windows machine.

I think this is a problem. I suspect that it is a big problem and that Macromedia needs to fix it. I'm only beginning to dabble in Flash and just learning about how to script Flash movies. I don't know if this security problem will affect movies that use SharedObject but do not explicitly open themselves up to scripting of that SharedObject. It could be that if you play a Flash-based game at Site C, site D could figure out a way to read your high score in that game.

Your thoughts are welcome in the comments, especially if you understand Flash and Flash scripting better than I do!

Client side sparkline images

| 2 Comments

Sparklines are a new graphical concept championed by Edward Tufte, author of a number of very cool books that you have probably already heard about. Sparklines are an idea from his forthcoming book, and he explains them in a draft chapter from that forthcoming book at sparklines.org.

If you're using a browser that understands the data: URL, here's an example of a sparkline:

Server load: 16.

Note, that this particular sparkline is hard-coded in this blog entry. The demos below show how they are dynamically generated.

As part of my newfound obsession with client-side drawing techniques (I really think it could change the web) I've created a way to generate sparkline images using client-side Java and JavaScript. This is proof-of-concept stage, but if you're running Firefox and have the Java plugin installed, click on these links to try out the demos:

  • spark.html: this demo uses LiveConnect to script Java directly. It does not use an applet at all. This means it will not work in IE. I don't know about other browsers' support for this kind of direct scripting of Java classes. This demo returns a PNG image encoded in a data: URL. This also means it won't work in IE, since IE does not support the data: scheme.
  • spark2.html: this demo uses a SparklineGenerator applet to create the PNG image, which it returns as a javascript: URL. This is supposed to be for compatibility with IE, but it still doesn't work in that browser for me. It could probably be made to work somehow... This demo also moves toward an unobtrusive JavaScript technique in which sparklines are coded with a new <sparkline> tag, which gets replaced by the image after document load by JavaScript and the applet.

You'll need to understand both Java and JavaScript to make use of this stuff. But if it interests you, you can use my code for any purpose as long as you attribute it to me.

Flash for client-side vector graphics!

| 7 Comments

In my previous entry, I asked about the possiblity of using Flash as a vector graphics engine, for scripting by client-side JavaScript code. With help from Geoff Stearns and his blog Deconcept I've figured out how to do it.

I've figured out how to do it in Flash 8, at least. Flash 8 has a new ExternalInterface API that transparently makes ActionScript methods callable from JavaScript. (It is possible, though not nearly so simple to do similar things in earlier versions of Flash.) Here is my trivial ActionScript file, which I named Canvas.as:

import flash.external.ExternalInterface;

class Canvas {
    static function main() {
        Stage.scaleMode = "noScale";
        Stage.align = "TL";
        ExternalInterface.addCallback("beginFill", _root, _root.beginFill);
        ExternalInterface.addCallback("beginGradientFill", _root,
                                      _root.beginGradientFill);
        ExternalInterface.addCallback("clear", _root, _root.clear);
        ExternalInterface.addCallback("curveTo", _root, _root.curveTo);
        ExternalInterface.addCallback("endFill", _root, _root.endFill);
        ExternalInterface.addCallback("lineTo", _root, _root.lineTo);
        ExternalInterface.addCallback("lineStyle", _root, _root.lineStyle);
        ExternalInterface.addCallback("moveTo", _root, _root.moveTo);
    }
}

I compiled this code with the open-source mtasc ActionScript compiler like this:

mtasc -swf Canvas.swf -main -version 8 Canvas.as

This produced the file Canvas.swf which you can download by clicking the link.

The ActionScript code doesn't do anything except make the Flash drawing API accesible to JavaScript. If you embed this SWF file in your web page, it is simply blank, until you draw something to it yourself. Here is a demo:

<embed src="Canvas.swf" quality=high bgcolor=#FFFFFF width="400" height="200"
name="canvas" align="" type="application/x-shockwave-flash"
pluginspage="http://www.macromedia.com/go/getflashplayer">

<p><button onclick="draw()">Draw in the Canvas</button>
<script>
function draw() {
    document.canvas.beginFill(0xAAAAFF, 100);
    document.canvas.lineStyle(5, 0x0000FF, 100);
    document.canvas.moveTo (10, 10);
    document.canvas.lineTo (200, 100);
    document.canvas.lineTo (10, 190);
    document.canvas.lineTo (10, 10);
    document.canvas.endFill();
}
</script>

This demo uses the <embed> tag instead of the <object> tag, so it won't run in IE. But I have tested it in Firefox, and it works. But only if you have Flash 8 installed. And Flash 8 is not available for Linux yet. If you've got Flash 8 running in Firefox (or Safari?) give the demo a try!

Comments, suggestions, improvements, or whatever are very welcome. I plan to tweak Canvas.as a bit to expose methods for adding text, but I think that will be straightforward. I was disappointed to discover that the Flash drawing API is not nearly as robust as that of the <canvas> tag or of SVG of VML. In particular all curves must be done with quadratic beziers. Cubic beziers, circles, arcs and so on must all be approximated with a single curveTo() function. So it might be worth adding some basic shape-drawing primitives (circles, rounded rectangles, etc) to Canvas.as as well.

Feel free to use this code (and the swf file) for any purpose, with attribution.

Flash for client-side vector graphics?

| 6 Comments

I know very little about Flash, but it seems to me that it would make a good substitute for the <canvas> tag as well as SVG and VML. From a basic perusal of the Macromedia web site, it appears that it is possible for client-side JavaScript to communicate with the ActionScript interpreter in the Flash plugin. If so, JavaScript ought to be able to get ActionScript to draw lines, curves, and do other vector-graphics type things.

ActionScript has an eval() function. I would think that it would be possible to create a tiny SWF file that does nothing more than define a hidden TextField object and an onChanged event listener for that field. The event listener would take the new value of the TextField and pass it to eval(). Client-side JavaScript would then set the value of the TextField with the TSetProperty method that is exported by the Flash player. And voila! Client-side JavaScript can then make pass arbitrary ActionScript commands to the Flash Player. This gives us scriptable client-side vector graphics that work anywhere Flash is installed.

Can anyone tell me why this wouldn't work? Is anyone already doing it? If you make this work and release your code openly, you'll get a link and an attribution in the next edition of my JavaScript book!

Canvas tag in Java and XBL

| 6 Comments

I think 2D graphics are a lot of fun, and have always loved the Java2D API. How cool is it, then, that Safari includes and Firefox 1.5 will include a new <canvas> tag that exposes a drawing API very, very similar to the Java2D API?

The canvas tag has the potential to revolutionize a lot of web applications. But for this to happen, it needs to be ported to browsers other than Safari and Firefox 1.5. I'm sure it can be done for IE, somehow, but I don't want to tackle that right now.

Instead, my contribution is to begin implementing the canvas tag for Firefox 1.0 using a Java applet and Mozilla's XBL binding language. This is just at proof-of-concept stage, but it is usable enough to make simple demos work. The java applet and XBL files are here. The canvas.html file in that directory is a simple demo. It doesn't seem to work online, but if you copy the files to a local directory, it should work. (I suspect, but don't know, that XBL bindings have to be installed locally to work for security reasons.)

To use this, compile the .java file to a .class file. Then define a simple stylesheet that tells Firefox to use the canvas.xbl file to implement the canvas tag. This is what I use:

<style>
canvas {
    -moz-binding: url('canvas.xbl#canvas');
    display:block;
}
</style>

Anyone want to take over work on this? You need to know Java and JavaScript, and know more about XBL than I do. And if you know something about whatever IE uses instead of XBL, that would be a big help, too... Drop me a line if you're interested!

XMLHttpRequest with <script> and PHP

| 7 Comments

Here is a very simple XMLHttpRequest utility function:

/**
 * Use XMLHttpRequest to fetch the contents of the specified URL using
 * an HTTP GET request.  When the response arrives, pass it (as plain
 * text) to the specified callback function.
 */
HTTP.getText = function(url, callback) {
    var request = HTTP.newRequest();
    request.onreadystatechange = function() {
	if (request.readyState == 4) {
	    if (request.status == 200) callback(request.responseText);
	}
    }
    request.open("GET", url);
    request.send(null);
};

This function assumes the presence of a HTTP.newRequest() function to abstract away the differences in creating an XMLHttpRequest object in IE and other browsers. (You've seen a function like this in every Ajax utility library you've looked at...)

Since XMLHttpRequest uses ActiveX in IE, it is unavailable if the user has disabled ActiveX for security reasons. In this situation, we can try to fall back on other means of scripting HTTP. Both <iframe> and <script> tags have src attributes that can generate HTTP GET requests when dynamically set. Let's start there and see if we can use these tags to create an analog to the HTTP.getText() method shown above. (Full compatibility with XMLHttpRequest is not possible with these techniques, however.)

The Back Button is not an Undo Button

| 9 Comments

When a web application uses XMLHttpRequest to retreive content for display to the user, no page load occurs, and therefore, the browser's Back button cannot be used to step backwards through the user's browsing history within the application. Much has been made of this Back button problem in Ajax applications. But I'm not convinced that it is anything to worry about.

Maybe usability testers who have worked with Ajax applications can tell me otherwise, but it just doesn't seem that confusing to me. When I zoom a map in Google maps, for exmaple, I simply don't expect the Back button to unzoom it. If I've just clicked the "+" button to increase the magnification of the map, why would I expect a button named "Back" to decrease the magnification? I'm zooming in and out, not back and forward...

One small insight I've had about thi s is that the browser's Back and Forward buttons are not, and should not be, Undo and Redo buttons for web applications. I expect that all but the most inexperienced users have internalized this distinction. Or they will, unless the designers of Ajax applications insist on making Back work like an undo function within their application.

As a corollary, allow me to suggest that wizard-style interactions, with "Next" and "Previous" buttons are not well suited to Ajax applications. Next and Previous are uncomfortably close to Forward and Back, and I think that users of such an application will (and should) reasonably expect that the browser's Back button will perform the same action as the wizard's Previous button. So if you're going for a wizard-style user-interface, skip the Ajax and just do plain old form submissions and page loads so that browser history works okay...

Other than that, I don't think we need to worry about the Back button. But take this advice with a grain of salt. I've performed absolutely no testing with real-world users.

XMLHttpRequest.readyState == 3

| 8 Comments

Microsoft invented the XMLHttpRequest, so they get to document it. Mozilla copies the Microsoft API and their documentation simply links to the Microsoft docs.

Unfortunately the Microsoft docs are lacking... (What is it about MSDN? Does it work better if you view it with IE? Trying to use it with Firefox on a Linux box is a uniformly frustrating experience. Hard to read, and even harder to navigate)

Here's what MSDN has to say about readyState values 2 and 3:

(2) LOADED: The send method has been called, but the status and headers are not yet available.
(3) INTERACTIVE: Some data has been received. Calling the responseBody and responseText properties at this state to obtain partial results will return an error, because status and response headers are not fully available.

The description of state 2 implies that the next state will be the one in which the status code and headers are avaialble. But then the documentation for state 3 just falls apart, saying that the body of the response is not available because the status and headers are not available.

This reads to me like a documentation mistake. In state 3 I would expect status and headers to be available, but I would not expect to be able to query the responseText property.

Has anyone figured out if it is okay to query the response headers in state 3? That is, is this a documentation error? Or does the documentation correctly describe an implementation error?

Update: In comments, Ian Hickson points out that the WhatWG draft spec for XMLHttpRequest addresses this precise question: in readyState 3, responseText should give us all text that has been downloaded so far, and getResponseHeader() and getResponseHeaders() should return any headers that have been downloaded so far. If we can assume that all headers will be in the first IP packet of the response, then those methods should work for readyState 3.

Appending array contents to another array

| 11 Comments

I would have sworn that there was a built in Array function for appending the contents of one array to another array.... But when I went to look it up, I found I was wrong.

Array.concat() concatenates the contents of two arays, but it creates and returns a new array rather than appending to the array on which it is invoked.

Array.push() and Array.splice() modify the array on which they are called, but append the array itself, rather than appending the contents of the array.

There isn't even an append() function in the Array Extras package coming in Firefox 1.5.

Here, therefore, is my solution to this problem:

// Append the elements of the array a to this array
Array.prototype.append = function(a) {
    Array.prototype.push.apply(this, a);
}

Example: using JavaScript in Java

| 2 Comments | 1 TrackBack

Java 6.0 ("Mustang") includes a JavaScript interpreter and a javax.script package for interacting with it. The code below is an example of how it works...

Synthetic tags and unobtrusive JavaScript

| 2 Comments

It occurs to me that it would be a useful convention for any script that creates and adds elements to the document to tag those elements by adding "synthetic" to the class attribute of the element

This way, other scripts that run later can identify elements that were not part of the original document. Some scripts will want to process syntehtic elements along with the originals, but some will want to skip those synthetic elements.

I don't have a compelling example use case to argue for this, but it just seems like as we start writing more and more useful unobtrusive scripts, we'll find that they interact with each other in unexpected ways. I haven't written any greasemonkey scripts myself, but I suspect that a convention like this would be helpful there, too...

Fake Blogs and JavaScript Decoding Challenge

| 5 Comments

If you, like me, use Technorati to find interesting blog entries tagged "javascript", then you've probably noticed in recent days that a site javascript-guide.info (I'm not going to give them a real link; you can type this URL in yourself) has had a lot of posts, but that they titles are kind of gibberish. Looking at the site, it appears to be a fake blog, with content that is some how automatically gleaned from elsewhere on the web. There are lots of ads on each page, so I suspect that this site exists to get Google AdSense clicks...

When I visited, I noticed a persistant "waiting for fueledstudios.com..." message in my browser's status line. So I used view source to find out what it was loading from that site. It turns out that the last think each page of this fake blog does is load a script from fueledstudios.com

This is where the JavaScript Decoding Challenge comes in. Take a look at the script. It is not heavily obfuscated, but whitespace has been stripped out. The name of the script indicates that it is tracking something. A glance at the script shows that it is doing something with the google adsense ads on the page. it also registers event handlers, uses setTimeout() to repeatedly do something, and communicates with its server by dynamically loading images that pass a lot of data in their URL.

This might all be perfectly benign. But I have the feeling that this site is doing something sleazy. It sure would be nice if we could tell Google that this site is violating their AdSense terms-of-service. That might cause the site to shut down and stop spamming Technorati with junk. So, this is the challenge: anyone want to sort out what this script actually does? I'm very curious, but can't spare the time...

Let me know if you figure anything out!

Another practical use for JavaScript closures

| 2 Comments

Vincenzo Alcamo wrote to me with another practical use for closures in JavaScript. Vincenzo is working on a JavaScript library he calls XMLLib, based on the Sarissa library. To prevent his library from cluttering the global namespace, Vinceno defines his symbols in his own XMLLib namespace, of course.

But he goes one step further. In Vincenzo's code, only publically exported methods and properties ever get stored in the XMLLib object. Internal, helper methods that are not intended for public use exist in a closure, where all the public methods can use them but where they are hidden from everyone else.

Schematically, the code looks like this:

// Create an empty namespace
XMLLIB = {}

(function() {  // anonymous function creates a closure for us
    // Thi s is a private method that stays hidden within the closure
    function private_utilty_method() { /* utility code here */ }

    // This method is exported into the XMLLib namespace, so it is a public method
    // But since it is defined here, it can call private methods like the one above.
    XMLLib.publicMethod = function() { /* ... */}
})();  // Close function definition and invoke it all at once

Contrast this approach to private symbols with that taken by JSAN. In that framework, a namespace may contain a mix of public and private symbols. The namespace also declares an array of symbols that should be exported by default, and an array of symbol that are allowed to be exported from the namespace. Any symbols excluded from these arrays are private, and the JSAN exporter functions will not copy them into the global namespace. That is, the JSAN framework does not have true privacy via closures, but defines a convention which, when followed, provides a measure of privacy.

Thanks for the tip, Vincenzo!

Borrowing methods instead of inheriting methods

| 8 Comments

The typical way to create new classes in JavaScript is by subclassing another class to inherit its methods. It occurs to me that this is not the only way. Since functions are data values in JavaScript, it is also possible to extend a class simply by copying methods from another class into it. I call this "borrowing" (although I suspect that someone else has already named it something else--let me know):

The code at the end of this postdemonstrates. It creates a simple Rectangle class. Then another simple class called GenericToString. This second class isn't good for much on its own, but serves as a "mixin" that can be borrowed by other classes. The next bit of code in the example is a function that does the borrowing. This is followed by a new class Rectangle2, which does nothing of its own, just borrows methods from the first two classes.

Update: I should add here that this method borrowing technique can be compared to multiple inheritance. The Rectangle2 class inherits methods from Object and borrows methods from two other classes. If there was a way of writing abstract methods in JavaScript (perhaps just throw "this method is abstract!") then borrowing methods from a class that defined abstract methods would be a little like implementing an interface in Java.

I'm interested in reader's thoughts on this technique. Is anything like this used in other languages? Has anyone given this an official-sounding name?

The code is in the extended entry...

JavaScript Module Conventions?

| 2 Comments

Unobtrusive JavaScript calls for JavaScript code to be removed from our HTML and placed in external .js files. At the same time, JavaScript frameworks and libraries are multiplying like crazy. More and more, we are going to be seeing web pages that load 2, 3, or more external .js files.

This means that we need to become disciplined about how we create those .js files, and adopt namespace conventions for these external modules of code so that two modules do not overwrite each others properties.

As far as I can tell, each JavaScript framework out there does this slightly differently. The most explicitly documented set of conventions I've seen are Casey West's rules for writing modules that work with his JSAN.use() function Casey's use() function is a perl-influenced function that loads (dynamically!) a .js module and then imports a set of symbols from the module into the global namespace. it is good stuff, but his module-structuring and namespace-creating rules are tied directly to his JSAN.use() code and I don't think they are general enough for people who want to write modules to be statically loaded with a <script> tag.. For example. a JSAN module defines the set of symbols that it can export, but the only way to import those symbols is via the use() function. There is not a separate import() function for importing symbols. without using use().

If you know of a well-articulated set of conventions for defining reusable modules of JS code, putting them in namespaces, and importing symbols, please add a comment to this post!

Here is my first cut at a list of requirements for a JavaScript module system:

  1. A .js module must not define more than one symbol in the global namespace. If it does define a symbol, that symbol should probably be the same as, or derived from, its filename.
  2. Any additional symbols defined by a module should be defined within a separate object, or "namespace".
  3. We need a way to selectively import symbols from a namespace into the global namespace. This is for convenience only; the methods deifned by a module should be written to work from their own namespace or from the global namespace.
    1. We could standardize an import() function for doing this importing. Or just create the necessary conventions, so that different frameworks can create their own import() methods.
    2. Modules should probably be allowed (but not required) to declare their own list of exported symbols (as JSAN modules do). And if such a list is defined, the import facility should not allow non-exported symbolsto be imported.
  4. For client-side programming, modules need a safe way to register code to be run in response to the onload event, without worrying that they will overwrite or be overwritten by the initialization code for some other module.
  5. There should be a standard way for a module to declare its name and version number.
  6. There should be a standard way for a module to register itself as loaded, and a standard way for a module to query the list of loaded modules (to verify that any modles it depends on are already present).

Please feel free to add your own ideas in the comments!

What should we call JavaScript pseudo-classes?

| 6 Comments

Like many others, I use the term "class" to informally describe the things we create in JavaScript using constructors and prototype objects. But JavaScript 2.0 is on the horizon, and since that version of the language has real classes, I want to start using a different term to describe JavaScript 1.x pseudo-classes.

Is anyone aware of a pre-existing convention that I can adopt? I've tried using "category" but I think it is too vague. My current feeling is that I should use the hypenated word "proto-type", although if I do this, I need to be careful not to confuse it with "the prototype object" that we use to create a proto-type.

If you have a thought or better suggestion, I'd love to hear about it. Just retaining our current usage of "class" is an option, too, of course.

Find the JavaScript bug

| 3 Comments

Can you spot the bug in the following code?

// Compute the sum of the elements in array a
function sum(a) {
    // Bonus feature: if we're passed more than one argument,
    // then sum the arguments of the array instead.
    if (arguments.length > 1) a = arguments;
    var total = 0;
    for(var i = 0; i < a.length; i++) total += a[i];
    return total;
}

Hint: the function works correctly if you pass an array, but not if invoked with more than one argument.

Answer follows...

Another Useful JavaScript Closure

| 9 Comments

I found another useful example involving closures. Bob Ippolito's python-style iteration framework includes this nifty code:

arrayLikeIterator = function (arrayLike) {
    var i = 0;
    return {
        'next': function () {
            if (i >= arrayLike.length) {
                throw StopIteration;
            }
            return arrayLike[i++];
        }
    };
};

There is lots more to Bob's iteration framework at his blog. The iteration stuff is part of Bob's larger framework, MochiKit, which looks quite interesting.

For the record, I disagree with Bob about throwing an exception at the end of iteration. I tihnk he'd be better of returning a unique sentinel value (but probably not null). His StopIteration error object could work just fine as a sentinel, if he'd return it instead of throwing it.

Update: after exchanging a number of emails with Bob, I now understand that his iterators are python-style iterators, intended to be used as part of a larger framework, and that they are to be treated as opaque values and passed to other functions that do the work of iterating them. That is, the end user of the iterators never has to catch the exception that the iterator throws. Bob has convinced me when an iterator is processed by a chain of composed functions, the use of an exception to end the iterator is the most efficient way to go. So, I drop my objection to throwing an exception to end iteration, as long as you use Bob's iterators in the python-based style he intends.

JavaScript Closures Example

I came up with the code below to demonstrate that two JavaScript closures can have the same scope chain. This gives them shared access to properties that are not accessible from anywhere else.

Here's the code:

//
// This function adds property accessor methods for a property with 
// the specified name to the object o.  The methods are named get<name>
// and set<name>.  If a predicate function is supplied, then the setter
// method uses it to test its argument for validity before storing it.
// If the predicate returns false, then the setter method throws an exception.
// 
// The unusual thing about this function is that the property value 
// that is manipulated by the getter and setter methods is not stored in
// the object o.  Instead, the value is stored only in a local variable
// in this function.  The getter and setter methods are also defined
// locally to this function, and therefore have access to this local variable.
// Note that the value is private to the two accessor methods, and it cannot
// be set or modified except through the setter.
// 
function makeProperty(o, name, predicate) {
    var value;  // This is the property value

    // The setter method simply returns the value
    o["get" + name] = function() { return value; }

    // The getter method stores the value or throws an exception if
    // the predicate rejects the value
    o["set" + name] = function(v) { 
        if (predicate && !predicate(v))
	    throw "set" + name + ": invalid value " + v;	
	else
            value = v;
    }
}

// The following code demonstrates the makeProperty() method 
var o = {};  // here is an empty object

// Add property accessor methods getName and setName()
// Ensure that only string values are allowed
makeProperty(o, "Name", function(x) { return typeof x == "string"; });

o.setName("Frank");  // Set the property value
print(o.getName());  // Get the property value
o.setName(0);        // Try to set a value of the wrong type

This example is simlar to Douglas Crockford's Private Members in JavaScript.

I don't think it is actually that useful in practice--I don't recommend that anyone start calling my makeProperty() function on their own objects! As far as I know, the most realistically useful application of JavaScript closures is Steve Yen's breakpoint() function.

WaSP tackles JavaScript

I've been turning my attention from Java to JavaScript in recent days.

I discovered this morning that the Web Standards Project (or WaSP) has turned its attention to JavaScript, as well. They have recently announced the launch of the DOM Scripting Task Force to promote "unobtrusive" JavaScript programming using the W3C DOM. See the Manifesto and their Definitions. There is not much else at the task force's site yet. Here's an interesting example of unobtrusive JavaScript in action, however.

If WaSP can do for JavaScript programming what they have done for CSS, this is a great thing for the web!

Books

Comprehensive coverage of Ruby 1.8 and 1.9

"The New Most Important Ruby Book"
Peter Cooper,
rubyinside.com

Completely updated for Ajax and Web 2.0

"A must-have reference"
Brendan Eich,
creator of JavaScript

The classic Java quick-reference

Advertising

Pages

Hosted By

Powered by Movable Type 4.21-en