Blog


Which Unit Testing Framework?

I'm in the process of working on, and improving, test suite support in TestSwarm (an upcoming project of mine). However, there isn't a lot of information on which unit testing frameworks developers actually use to test their code (whereas there is more information on which JavaScript libraries are used).

It will be of great help to me if you could quickly fill out the question below. I will release the results of the survey as soon as possible. Thanks!

» Which JavaScript Unit Testing Frameworks do you use?

More information on the frameworks listed above:

Tags: testing, javascript

JSConf Talk: Games, Performance, TestSwarm

The video from my talk at JSConf has been posted. Thanks to Chris for organizing the conference and the excellent quality of the video.

The description from the JSConf site summarizes the talk well:

John Resig presents his mystery topic, which is actually three topics that strike his interest. First up is measuring performance and a quick introduction to benchmarking (and its positives and negatives). This is followed by JavaScript Games which he unveils some super cool hidden functionality (cheat codes++) on the jQuery web site. This is followed up by the introduction of John's distributed continuous test framework platform, Test Swarm. It is jam packed with Nirvana and goodness so be sure to watch both parts.

Part 1: Measuring JavaScript Performance, JavaScript Games


Part 2: Distributed JavaScript Testing, Q&A


Additionally, the slides from the talk are up on Slideshare.


Tags: javascript, presentation, conferences

Unimpressed by NodeIterator

I just posted a run down of some of the new DOM Traversal APIs in Firefox 3.5. The first half of the post is mostly a recap of my old Element Traversal API post.

The second half of the post is all about the new NodeIterator API that was just implemented. For those that are familiar with some of the DOM TreeWalker APIs this will look quite familiar.

It's my opinion, though, that this API is, at best, bloated, and at worst incredibly misguided and impractical for day-to-day use.

Observe the method signature of createNodeIterator:

var nodeIterator = document.createNodeIterator(
  root, // root node for the traversal
  whatToShow, // a set of constants to filter against
  filter, // an object with a function for advanced filtering
  entityReferenceExpansion // if entity reference children so be expanded
);

This is excessive for what should be, at most, a simple way to traverse DOM nodes.

To start, you must create a NodeIterator using the createNodeIterator method. This is fine except this method only exists on the Document node - which is especially strange since the first argument is the node which should be used as the root of the traversal. The first argument shouldn't exist and you should be able to call the method on any DOM element, document, or fragment.

Second, in order to specify which types of nodes you wish to see you need to provide a number (which is the result of the addition of various constants) that the results will be filtered against. This is pretty insane so let me break this down. The NodeFilter object contains a number of properties representing the different types of nodes that exist. Each property has a number associated with it (which makes sense, this way the method can uniquely identify which type of node to look for). But then the crazy comes in: In order to select multiple, different, types of nodes you must OR together the properties to creating a resulting number that'll be passed in.

For example if you wanted to find all elements, comments, and text nodes you would do:

NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT

I'm not sure if you can get a much more counter-intuitive JavaScript API than that (you can certainly expect little, to no, common developer adoption, that's for sure).

Next, the filter argument accepts an object that has a method (called acceptNode) which is capable of further filtering the node results before being returned from the iterator. This means that the function will be called on every applicable node (as specified by the previous whatToShow argument).

Two points to consider:

  • The filter argument must be an object with a property named 'acceptNode' that has a function as a value. It can't just be a function for filtering, it must be enclosed in a wrapper object. Update: Actually, this isn't true - at least with Mozilla's implementation you can pass in just a function. Thanks for the tip, Neil!
  • The argument is required (even though you can pass in null, making it equivalent to accepting all nodes).

The last argument, entityReferenceExpansion, comes in to play when dealing with XML entities that also contain sub-nodes (such as elements). For example, with XML entities, it's perfectly valid to have a declaration like <!ENTITY aname "<elem>test</elem>"> and then later in your document have &aname; (which is expanded to represent the element). While this may be useful for XML documents it is way out of the scope of most web content (thus the argument will likely always be false).

So, in summary, createNodeIterator has four arguments:

  • The first of which can be removed (by making the method available on elements, fragments, and documents).
  • The second of which is obtuse and should be optional (especially in the case where all nodes are to be matched.
  • The third which requires a superfluous object wrapping and should be optional.
  • The fourth of which should be optional.

None of this actually takes into account the actual iteration process. If you look at the specification you can see that all the examples are in Java - and when seeing this a lot of the API decisions start to make more sense (not that it really applies to the world of web-based development, though). In JavaScript one doesn't really use iterators, more typically an array is used instead. (In fact a number of helpers have been added in ECMAScript 5 which make the iteration and filtering process that much simpler.)

I'd like to propose the following, new, API that would exist in place of the NodeIterator API (dramatically simplifying most common interactions, especially on the web).

// Get all nodes in the document
document.getNodes();

// Get all comment nodes in the document
document.getNodes( Node.COMMENT_NODE );

// Get all element, comment, and text nodes in the document
document.getNodes( Node.ELEMENT_NODE, Node.COMMENT_NODE, Node.TEXT_NODE );

I'd also like to propose the following helper methods:

// Get all comment nodes in the document
document.getCommentNodes();

// Get all text nodes in a document
document.getTextNodes();

Beyond finding elements, finding comments and text nodes are the two most popular queries types that I see requested.

Consider the code that would be required to recreate the above using NodeIterator:

// Get all nodes in the document
document.createNodeIterator(document, NodeFilter.SHOW_ALL, null, false);

// Get all comment nodes in the document
document.createNodeIterator(document, NodeFilter.SHOW_COMMENT, null, false);

// Get all element, comment, and text nodes in the document
document.createNodeIterator(document,
    NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT,
    null, false
);

This proposed API would return an array of DOM nodes as a result (instead of an NodeIterator object). You can compare the difference in results between the two APIs:

NodeIterator API

var nodeIterator = document.createNodeIterator(
    document,
    NodeFilter.SHOW_COMMENT,
    null,
    false
);

var node;

while ( (node = nodeIterator.nextNode()) ) {
    node.parentNode.removeChild( node );
}

Proposed API

document.getCommentNodes().forEach(function(node){
    node.parentNode.removeChild( node );
});

Another example, if we were to find all elements with a node name of 'A'.

NodeIterator API

var nodeIterator = document.createNodeIterator(
    document,
    NodeFilter.SHOW_ELEMENT,
    {
        acceptNode: function(node){
          return node.nodeName.toUpperCase() === "A";
        }
    },
    false
);

var node;

while ( (node = nodeIterator.nextNode()) ) {
    node.className = "found";
}

Proposed API

document.getNodes( Node.ELEMENT_NODE ).forEach(function(node){
    if ( node.nodeName.toUpperCase() === "A" )
        node.className = "found";
});

Almost always, when finding some of the crazy intricacies of the DOM or CSS, you'll find a legacy of XML documents and Java applications - neither of which have a strong application to the web as we know it or to the web as it's progressing. It's time to divorce ourselves from these decrepit APIs and build ones that are better-suited to web developers.

Update: An even better alternative (rather than using constants representing node types) would be something like the following:

document.getNodes( Element, Comment, Text );

Just refer back to the back objects representing each of the types that you want.

Tags: dom, javascript, w3c

ECMAScript 5 Strict Mode, JSON, and More

Previously I analyzed ECMAScript 5's Object and Property system. This is a huge new aspect of the language and deserved its special consideration.

There are a number of other new features and APIs that need attention, as well. The largest of which are Strict Mode and native JSON support.

Strict Mode

Strict Mode is a new feature in ECMAScript 5 that allows you to place a program, or a function, in a "strict" operating context. This strict context prevents certain actions from being taken and throws more exceptions (generally providing the user with more information and a tapered-down coding experience).

Since ECMAScript 5 is backwards-compatible with ECMAScript 3, all of the "features" that were in ECMAScript 3 that were "deprecated" are just disabled (or throw errors) in strict mode, instead.

Strict mode helps out in a couple ways:

  • It catches some common coding bloopers, throwing exceptions.
  • It prevents, or throws errors, when relatively "unsafe" actions are taken (such as gaining access to the global object).
  • It disables features that are confusing or poorly thought out.

Most of the information about strict mode can be found in the ES5 specification [PDF] on page #223.

It should be noted that ECMAScript 5's strict mode is different from the strict mode available in Firefox (which can be turned on by going to about:config and enabled javascript.options.strict). ES5's strict mode complains about a completely different set of potential errors (whereas Firefox's existing strict mode tries to enforce some good practices, only).

How do you enable strict mode?

Simple. Toss this at the top of a program to enable it for the whole script:

"use strict";

Or place it within a function to turn on strict mode only within that context.

function imStrict(){
  "use strict";
  // ... your code ...
}

Note the syntax that's used to enable strict mode (I love this!). It's simply a string in a single statement that happens to contain the contents "use strict". No new syntax is introduced in order to enable strict mode. This is huge. This means that you can turn strict mode on in your scripts - today - and it'll have, at worst, no side effect in old browsers.

As you may note from the examples here and in the previous post there are virtually no new syntax additions or changes to the language in ECMAScript 5. This means that you can write your ES5 scripts in a manner that will be able to gracefully degrade for older useragents - something that wasn't possible with ECMAScript 4. The way in which strict mode is enabled is a great illustration of that point in practice.

A neat aspect of being able to define strict mode within a function is that you can now define complete JavaScript libraries in a strict manner without affecting outside code.

// Non-strict code...

(function(){
  "use strict";
 
  // Define your library strictly...
})();

// Non-strict code...
 

A number of libraries already use the above technique (wrapping the whole library with an anonymous self-executing function) and they will be able to take advantage of strict mode very easily.

So what changes when you put a script into strict mode? A number of things.

Variables and Properties

An attempt to assign foo = "bar"; where 'foo' hasn't been defined will fail. Previously it would assign the value to the foo property of the global object (e.g. window.foo), now it just throws an exception. This is definitely going to catch some annoying bugs.

Any attempts to write to a property whose writable attribute is set to false, delete a property whose configurable attribute is set to false, or add a property to an object whose extensible attribute is set to false will result in an error (these attributes were discussed previously). Traditionally no error will be thrown when any of these actions are attempted, it will just fail silently.

Deleting a variable, a function, or an argument will result in an error.

var foo = "test";
function test(){}

delete foo; // Error
delete test; // Error

function test2(arg) {
    delete arg; // Error
}

Defining a property more than once in an object literal will cause an exception to be thrown

// Error
{ foo: true, foo: false }

eval

Virtually any attempt to use the name 'eval' is prohibited - as is the ability to assign the eval function to a variable or a property of an object.

// All generate errors...
obj.eval = ...
obj.foo = eval;
var eval = ...;
for ( var eval in ... ) {}
function eval(){}
function test(eval){}
function(eval){}
new Function("eval")

Additionally, attempts to introduce new variables through an eval will be blocked.

eval("var a = false;");
print( typeof a ); // undefined
 

Functions

Attempting to overwrite the arguments object will result in an error:
arguments = [...]; // not allowed

Defining identically-named arguments will result in an error function( foo, foo ) {}.

Access to arguments.caller and arguments.callee now throw an exception. Thus any anonymous functions that you want to reference will need to be named, like so:

setTimeout(function later(){
  // do stuff...
  setTimeout( later, 1000 );
}, 1000 );

The arguments and caller properties of other functions no longer exist - and the ability to define them is prohibited.

function test(){
  function inner(){
    // Don't exist, either
    test.arguments = ...; // Error
    inner.caller = ...; // Error
  }
}

Finally, a long-standing (and very annoying) bug has been resolved: Cases where null or undefined is coerced into becoming the global object. Strict mode now prevents this from happening and throws an exception instead.

(function(){ ... }).call( null ); // Exception
 

with(){}

with(){} statements are dead when strict mode is enabled - in fact it even appears as a syntax error. While the feature was certainly mis-understood and possibly mis-used I'm not convinced that it's enough to be stricken from the record.

The changes made in ECMAScript 5 strict mode are certainly varied (ranging from imposing stylistic preferences, like removing with statements, to fixing legitimately bad language bugs, like the ability to redefine properties in object literals). It'll be interesting to see how people begin to adopt these points and how it'll change JavaScript development.

All that being said, I'm fairly certain that jQuery is ES5-Strict compatible right now. Once an implementation of the language is made available (so that that premise may be tested) I'll happily switch jQuery over to working exclusively in strict mode.

JSON

The second major feature of the language is the addition of native JSON support to the language.

I've been championing this move for a long time and I'm glad to see it finally arrive in a specification.

In the meantime PLEASE start migrating your JSON-using applications over to Crockford's json2.js. It is fully compatible with the ECMAScript 5 specification and gracefully degrades if a native (faster!) implementation exists.

In fact, I just landed a change in jQuery yesterday that utilizes the JSON.parse method if it exists, now that it has been completely specified.

There are two primary methods for handling JSON: JSON.parse (which converts a JSON string into a JavaScript object) and JSON.stringify (which convert a JavaScript object into a serialized string).

JSON.parse( text )

Converts a serialized JSON string into a JavaScript object.

var obj = JSON.parse('{"name":"John"}');
// Prints 'John'
print( obj.name );

JSON.parse( text, translate )

Use a translation function to convert values or remove them entirely.

function translate(key, value) {
  if ( key === "name" ) {
    return value + " Resig";
  }
}

var obj = JSON.parse('{"name":"John","last":"Resig"}', translate);
// Prints 'John Resig'
print( obj.name );

// Undefined
print( obj.last );

JSON.stringify( obj )

Convert an object into a serialized JSON string.

var str = JSON.stringify({ name: "John" });
// Prints {"name":"John"}
print( str );

JSON.stringify( obj, ["white", "list"])

Serialize only a specific white list of properties.

var list = ["name"];
var str = JSON.stringify({name: "John", last: "Resig"}, list);
// Prints {"name":"John"}
print( str );

JSON.stringify( obj, translate )

Serializes the object using a translation function.

function translate(key, value) {
  if ( key === "name" ) {
    return value + " Resig";
  }
}

var str = JSON.stringify({"name":"John","last":"Resig"}, translate);
// Prints {"name":"John Resig"}
print( str );

JSON.stringify( obj, null, 2 )

Adds the specified number of spaces to the output, printing it evenly.

var str = JSON.stringify({ name: "John" }, null, 2);
// Prints:
// {
//   "name": "John"
// }
print( str );

JSON.stringify( obj, null, "\t" )

Uses the specified string to do the spacing.

var str = JSON.stringify({ name: "John" }, null, "\t");
// Prints:
// {\n\t"name": "John"\n}
print( str );

Additionally, a few new generic methods have been added to some of the base objects but, frankly, they aren't that interesting. The results from String, Boolean, and Number are just equivalent to calling .valueOf() and the result from Date is equivalent to calling .toISOString()

// Yawn...
String.prototype.toJSON
Boolean.prototype.toJSON
Number.prototype.toJSON
Date.prototype.toJSON

.bind()

A welcomed addition to the language is a built-in .bind() method for enforcing the context of a function (virtually identical to Prototype's .bind implementation).

Function.prototype.bind(thisArg, arg1, arg2....)

Enforces the 'this' of the specified function to a specific object - and passing in any specified arguments.

var obj = {
  method: function(name){
    this.name = name;
  }
};

setTimeout( obj.method.bind(obj, "John"), 100 );

Considering how long this function (and its equivalents) have been around it's a welcome addition to the language.

Date

Dates are now capable of both parsing and outputting ISO-formatted dates. Thank goodness, about time. rimshot

The Date constructor now attempts to parse the date as if it was ISO-formatted, first, then moves on to the other inputs that it accepts.

Additionally, date objects now have a new .toISOString() method that outputs the date in an ISO format.

var date = new Date("2009-05-21T16:06:05.000Z");

// Prints 2009-05-21T16:06:05.000Z
print( date.toISOString() );

.trim()

A native, built-in, .trim() is now included for strings. Works identically to all the other trim methods out there - with the potential to possibly work faster.

Steven Levithan has discussed the trim method in great depth.

Array

The JavaScript Array Extras that've been around for, what seems like, forever are finally formally specified. This includes the following methods: indexOf, lastIndexOf, every, some, forEach, map, filter, reduce, and reduceRight.

Additionally a new Array.isArray method is included, providing functionality very similar to the following:

Array.isArray = function( array ) {
  return Object.prototype.toString.call( array ) === "[object Array]";
};

Altogether I think ECMAScript 5 makes for an interesting package. It isn't the massive leap that ECMAScript 4 promised but it is a series of respectable improvements that reduces the number of obvious bugs while making the language safer and faster. I'm looking forward to when some implementations start to go public.

Tags: ecmascript, javascript

ECMAScript 5 Objects and Properties

ECMAScript 5 is on its way. Rising from the ashes of ECMAScript 4, which got scaled way back and became ECMAScript 3.1, which was then re-named ECMAScript 5 (more details)- comes a new layer of functionality built on top of our lovable ECMAScript 3.

Update: I've posted more details on ECMAScript 5 Strict Mode, JSON, and More.

There are a few new APIs included in the specification but the most interesting functionality comes into play in the Object/Property code. This new code gives you the ability to dramatically affect how users will be able to interact with your objects, allowing you to provide getters and setters, prevent enumeration, manipulation, or deletion, and even prevent the addition of new properties. In short: You will be able to replicate and expand upon the existing JavaScript-based APIs (such as the DOM) using nothing but JavaScript itself.

Perhaps best of all, though: These features are due to arrive in all major browsers. All the major browser vendors worked on this specification and have agreed to implement it in their respective engines. The exact timeframe isn't clear yet, but it's going to be sooner, rather than later.

There doesn't appear to exist a full implementation of ES5 at this point, but there are a few in the works. In the meantime you can read the ECMAScript 5 specification (PDF - I discuss pages 107-109 in this post) or watch the recent talk by some of the ECMAScript guys at Google.

Note: I've provided a couple simple, example, implementations for these methods to illustrate how they might operate. Almost all of them require other, new, methods to work correctly - and they are not implemented to match the specification 100% (for example there is no error checking).

Objects

A new feature of ECMAScript 5 is that the extensibility of objects can now be toggled. Turning off extensibility can prevent new properties from getting added to an object.

ES5 provides two methods for manipulating and verifying the extensibility of objects.

Object.preventExtensions( obj )
Object.isExtensible( obj )

preventExtensions locks down an object and prevents and future property additions from occurring. isExtensible is a way to determine the current extensibility of an object.

Example Usage:

var obj = {};

obj.name = "John";
print( obj.name );
// John

print( Object.isExtensible( obj ) );
// true

Object.preventExtensions( obj );

obj.url = "http://ejohn.org/"; // Exception in strict mode

print( Object.isExtensible( obj ) );
// false
 

Properties and Descriptors

Properties have been completely overhauled. No longer are they the simple value associated with an object - you now have complete control over how they can behave. With this power, though, comes increased complexity.

Object properties are broken down into two portions.

For the actual "meat" of a property there are two possibilities: A Value (a "Data" property - this is the traditional value that we know and love from ECMAScript 3) or a Getter and Setter (an "Accessor" property - we know this from some modern browsers, like Gecko and WebKit).

  • Value. Contains the value of the property.
  • Get. The function that will be called when the value of the property is accessed.
  • Set. The function that will be called when the value of the property is changed.

Additionally, properties can be...

  • Writable. If false, the value of the property can not be changed.
  • Configurable. If false, any attempts to delete the property or change its attributes (Writable, Configurable, or Enumerable) will fail.
  • Enumerable. If true, the property will be iterated over when a user does for (var prop in obj){} (or similar).

Altogether these various attributes make up a property descriptor. For example, a simple descriptor might look something like the following:

{
  value: "test",
  writable: true,
  enumerable: true,
  configurable: true
}

The three attributes (writable, enumerable, and configurable) are all optional and all default to true. Thus, the only property that you'll need to provide will be, either, value or get and set.

You can use the new Object.getOwnPropertyDescriptor method to get at this information for an existing property on an object.

Object.getOwnPropertyDescriptor( obj, prop )

This method allows you to access the descriptor of a property. This method is the only way to get at this information (it is, otherwise, not available to the user - these don't exist as visible properties on the property, they're stored internally in the ECMAScript engine).

Example Usage:

var obj = { foo: "test" };

print(JSON.stringify(
  Object.getOwnPropertyDescriptor( obj, "foo" )
));
// {"value": "test", "writable": true,
//  "enumerable": true, "configurable": true}
 

Object.defineProperty( obj, prop, desc )

This method allows you to define a new property on an object (or change the descriptor of an existing property). This method accepts a property descriptor and uses it to initialize (or update) a property.

Example Usage:

var obj = {};

Object.defineProperty( obj, "value", {
  value: true,
  writable: false,
  enumerable: true,
  configurable: true
});

(function(){
  var name = "John";
 
  Object.defineProperty( obj, "name", {
    get: function(){ return name; },
    set: function(value){ name = value; }
  });
})();

print( obj.value )
// true

print( obj.name );
// John

obj.name = "Ted";
print( obj.name );
// Ted

for ( var prop in obj ) {
  print( prop );
}
// value
// name

obj.value = false; // Exception if in strict mode

Object.defineProperty( obj, "value", {
  writable: true,
  configurable: false
});

obj.value = false;
print( obj.value );
// false

delete obj.value; // Exception
 

Object.defineProperty is a core method of the new version of ECMAScript. Virtually all the other major features rely upon this method existing.

Object.defineProperties( obj, props )

A means of defining a number of properties simultaneously (instead of individually).

Example Implementation:

Object.defineProperties = function( obj, props ) {
  for ( var prop in props ) {
    Object.defineProperty( obj, prop, props[prop] );
  }
};

Example Usage:

var obj = {};

Object.defineProperties(obj, {
  "value": {
    value: true,
    writable: false
  },
  "name": {
    value: "John",
    writable: false
  }
});

Property descriptors (and their associated methods) is probably the most important new feature of ECMAScript 5. It gives developers the ability to have fine-grained control of their objects, prevent undesired tinkering, and maintaining a unified web-compatible API.

New Features

Building on top of these new additions some interesting new features have been introduced into the language.

The following two methods are very useful for collecting arrays of all the properties on an object.

Object.keys( obj )

Returns an array of strings representing all the enumerable property names of the object. This is identical to the method included in Prototype.js.

Example Implementation:

Object.keys = function( obj ) {
  var array = new Array();
  for ( var prop in obj ) {
    if ( obj.hasOwnProperty( prop ) ) {
      array.push( prop );
    }
  }
  return array;
};

Example Usage:

var obj = { name: "John", url: "http://ejohn.org/" };

print( Object.keys(obj).join(", ") );
// name, url
 

Object.getOwnPropertyNames( obj )

Nearly identical to Object.keys but returns all property names of the object (not just the enumerable ones).

An implementation isn't possible with regular ECMAScript since non-enumerable properties can't be enumerated. The output and usage is otherwise identical to Object.keys.

Object.create( proto, props )

Creates a new object whose prototype is equal to the value of proto and whose properties are set via Object.defineProperties( props ).

A simple implementation would look like this (requires the new Object.defineProperties method).

Example Implementation:

Object.create = function( proto, props ) {
  var obj = new Object();
  obj.__proto__ = proto;

  if ( typeof props !== "undefined" ) {
    Object.defineProperties( obj, props );
  }
 
  return obj;
};

Note: The above code makes use of the Mozilla-specific __proto__ property. This property gives you access to the internal prototype of an object - and allows you to set its value, as well. The ES5 method Object.getPrototypeOf allows you to access this value but not set its value - thus the above method cannot be implement in a generic, spec-compatible, manner.

I discussed Object.getPrototypeOf previously so I won't bother discussing it again here.

Example Usage:

function User(){}
User.prototype.name = "Anonymous";
User.prototype.url = "http://google.com/";

var john = Object.create(new User(), {
  name: { value: "John", writable: false },
  url: { value: "http://google.com/" }
});

print( john.name );
// John

john.name = "Ted"; // Exception if in strict mode
 

Object.seal( obj )
Object.isSealed( obj )

Sealing an object prevents other code from deleting, or changing the descriptors of, any of the object's properties - and from adding new properties.

Example Implementation:

Object.seal = function( obj ) {
  var props = Object.getOwnPropertyNames( obj );
 
  for ( var i = 0; i < props.length; i++ ) {
    var desc = Object.getOwnPropertyDescriptor( obj, props[i] );
   
    desc.configurable = false;
    Object.defineProperty( obj, props[i], desc );
  }
 
  return Object.preventExtensions( obj );
};

You would seal an object if you want its existing properties to stay intact, without allowing for new additions, but while still allowing the user to write to or edit the properties.

Object.freeze( obj )
Object.isFrozen( obj )

Freezing an object is nearly identical to sealing it but with the addition of making the properties un-editable.

Example Implementation:

Object.freeze = function( obj ) {
  var props = Object.getOwnPropertyNames( obj );
 
  for ( var i = 0; i < props.length; i++ ) {
    var desc = Object.getOwnPropertyDescriptor( obj, props[i] );
   
    if ( "value" in desc ) {
      desc.writable = false;
    }
   
    desc.configurable = false;
    Object.defineProperty( obj, props[i], desc );
  }
 
  return Object.preventExtensions( obj );
};

Freezing an object is the ultimate form of lock-down. Once an object has been frozen it cannot be unfrozen - nor can it be tampered in any manner. This is the best way to make sure that your objects will stay exactly as you left them, indefinitely.

All together these changes are very exciting, they provide you with an unprecedented level of control over the objects that you produce. The best aspect, though, is that you will be able to use these features to build larger and more complex features in pure ECMAScript (such as building new DOM modules, or moving more browser APIs into pure-JavaScript). And since all the browsers are on board this is absolutely something that we can look forward to.

Tags: javascript, ecmascript

How do Mobile Browsers Behave?

One of my favorite sources of active mining is that of Peter-Paul Koch digging in to mobile browsers and how they behave. Sponsored by Vodaphone to do a study of various mobile devices and their respective browsers, PPK has been doing some serious analysis of what the landscape looks like.

Armed with a battery of tests he analyzes the various browsers manually (a painstaking task) but it yields some sweet fruit:

He breaks down the results into three areas (note: The results are very much still a work in progress, as noted by PPK, so please be aware of that before making any specific decisions on implementation or usability):

  • Mobile JavaScript/CSS Tests - These are the most comprehensive tests, analyzing a number of common DOM methods, Ajax, touch events, keyboard events, font styling, and custom events. Scanning the tables of results should be able to give you a pretty good picture of what mobile browsers are like.
  • Mobile CSS - Covering everything from CSS selectors (new and old) along with basic and advanced styling techniques.
  • Mobile W3C CSSOM - Covers aspects like screen size, mouse position, document size, and scroll offset.

In general, the results are terribly painful. The majority of the devices and browsers available today are a complete mess. Thankfully smart devices are making solid inroads bringing along good-quality browsers (WebKit-based browsers and Opera Mobile) but it's going to be a while before those devices are widely available.

Peter-Paul gave two follow-up talks on mobile browser testing, at Google and at Yahoo, that are worth watching, for additional details.

Google Talk on Mobile Browsers


Yahoo Talk (also discusses mobile browsers)


PPK is also organizing the Fronteers conference, taking place this fall in Amsterdam. I plan on attending and speaking, as well.

Tags: browsers, css, javascript, mobile

New Processing.js and Sizzle.js Sites

Thanks to some generous contributions, there now exist well-designed web sites for two projects of mine: Processing.js and Sizzle.js.

New Processing.js Site

Design and logo by Alistair MacDonald (on Twitter)

Processing.js was released almost a year ago (May 8th of last year) and it finally has an official web site. At this point the project is being primarily maintained by Alistair MacDonald (on Twitter) with active discussions taking place on the Processing.js Google Group.

On the new site you can see an an exhibition of cool Processing.js code, a full API reference, and a number of demos from the Processing.org site.

I especially like the fact that the header of the site is a live Processing.js demo. Thanks Alistair for the great site!

New Sizzle.js Site

Design by Grégoire Dierendonck and Pierre Bertet, logo by Micheil Smith.

Sizzle had a crude site when it was released back in January of this year but it has now been overhauled and given a proper logo thanks to Grégoire Dierendonck, Pierre Bertet, and Micheil Smith.

All of the Sizzle API documentation is located over on Github. Be sure to check out the Sizzle.js Google Group where active discussions are taking place.

Tags: javascript, sizzle, processing

More Secrets of JavaScript Libraries

This past weekend I had the pleasure of attending and presenting at the annual SXSW conference, down in Austin, TX. I participated in a panel discussion called 'More Secrets of JavaScript Libraries' (a follow-up panel to last year's talk). The synopsis was as follows:

In a reprise from last year's popular panel - the JavaScript libraries authors are getting together again to impart their what they've learned from their experience in developing solid, world-class, JavaScript libraries. Covering everything from advanced aspects of the JavaScript language, to handling cross-browser issues, all the way up to packaging and distribution. A complete set of knowledge for a JavaScript developer.

The talks went really well - we each gave a quick 10 minute presentation on a topic that interested us and finished up with some Q&A. The individual talks were as follows:

  • Getting Loaded (All about network performance and file loading) - by Nate Koechley of YUI.
  • Meta-Language Frameworks (Talking about the abstractions provided by frameworks) - by Andrew Dupont of Prototype.
  • Real World Accessibility (A quick examination of the upcoming ARIA specification) - by Becky Gibson of IBM and Dojo.
  • Performance and Testing (Looking at various performance analysis and testing techniques) - by John Resig of jQuery.

The full presentation and audio can be found online.

More information about my talk can be found in my follow-up post: JavaScript Testing Does Not Scale.

Tags: jslibs, conferences, javascript, panels

· « Previous entries

JavaScript Books

Secrets of the JavaScript Ninja

JavaScript Secrets

Secret techniques of top JavaScript programmers. Coming Fall 2009.

Pro JavaScript Techniques

Pro JavaScript

The best techniques for professional JavaScript. Published by Apress.

Micro Updates

John Resig Twitter Updates

@jeresig

Infrequent, short, updates and links.

JavaScript Jobs



Hosting provided by: Ruby Hosting by Engine Yard