Document Information

Last modified:
2007/12/12 11:01 by wpbasti

JavaScript Best Practises

As your qooxdoo application evolves, it is getting more and more important to know about code optimization techniques. This page will not teach you how to write qooxdoo applications, but it will show you how to avoid slow JavaScript code in general.

Temporary references

The object oriented nature of JavaScript often misleads the developer to make extensive use of the .-operator to access nested object properties. However, this can result in bad performance of your JavaScript code, because all the references have to be resolved at runtime.

Look at the following snippet:

anObject.aReference.anotherReference.someThing = true;
anObject.aReference.anotherReference.someThingElse = 3.141;
anObject.aReference.anotherReference.callSomeMethod();
anObject.aReference.anotherReference.callAnotherMethod();

With each statement above, the JavaScript interpreter first has to resolve the reference to anotherReference before it can access its properties or methods. One can imagine that this code won’t perform very well.

The following snippet shows a modification of the code above that uses a temporary reference to solve the problem:

var tmpReference = anObject.aReference.anotherReference;
tmpReference.someThing = true;
tmpReference.someThingElse = 3.141;
tmpReference.callSomeMethod();
tmpReference.callAnotherMethod();

This time, the nested access is only made once and the resulting object is stored in a temporary variable. The second snippet is not only executed faster, it is also easier to understand.

Please do not use JavaScript’s with statement. According to the Mozilla Core JavaScript Reference this has a negative impact on performance: “with forces the specified object to be searched first for all unqualified name lookups. Therefore all identifiers that match formal function argument and declared local variable names will be found more slowly in a with block.”

Loop-optimization

The concept of loops is usually well know among developers, but coming from a compiled language like C, C++, Java and alike, developers need to be aware of certain bottlenecks a purely interpreted language like JavaScript has.

Look at the following snippet:

for(var i=0; i < someArray.length; i++){ }

At first glance, this looks like a good old for-loop and indeed it is. Now imagine the steps a JavaScript interpreter has to do on each iteration. Everytime an iteration is finished, the interpreter has to test against the loop’s condition. In the snippet above this would mean that the interpreter had to calculate the length of the array object again and again.

This can be useful in special cases, where the length of the array changes during the loops execution. But commonly, the size of the array doesn’t change at all. Look at the next snippet to see a better performing implementation of the for-loop:

for(var i=0, l = someArray.length; i < l; i++){ }

This time, the length of the array only has to be calculated once, which in turn saves one statement on each iteration. As a result, the whole execution of the loop is faster, because the redundant loop-condition is avoided.

Delete versus null-assignment

JavaScript comes with its own delete operator to delete a reference or value of an object, hashmap or array. The operator returns true if the specified object was successfully deleted, otherwise it returns false. delete makes values undefined. However, this comes at a certain performace cost and in reality, few developers make use of the return values.

ns.obj = new Object();
delete ns.obj;

A better approach is to delete the value by assigning it null. The assignment is much faster and has basically the same result. Instead of undefined the value is null afterwards.

ns.obj = new Object();
ns.obj = null;

So if you want to delete a JavaScript object and you don’t really need delete‘s features, then the assignment of null is a better performing choice.

One difference between both approaches is however that delete also removes the field, not just the value. delete this way directly manipulates the available keys. When a key is deleted, the iteration using a for-in loop do not respect this one anymore, while resetting a value using a null value keeps the key and this way the iteration also loops over this key.

Equality versus Identity

JavaScript comes with two different types of comparison operators. One checking for expressions’ equality, the other checking for expressions’ identity.

Equality

In JavaScript, equality is tested using == and its counterpart !=, whereby JavaScript internally does some implicit type conversion to bring both types into a comparable format.

var num = 42;
var str = "42";
alert(num == str); //prints "true" in an alert box

The implicit conversion follows the following rules:

  • If the types of the two expressions are different, attempt to convert them to string, number, or Boolean.
  • NaN is not equal to anything including itself.
  • Negative zero equals positive zero.
  • null equals both null and undefined.
  • Values are considered equal if they are identical strings, numerically equivalent numbers, the same object, identical Boolean values, or (if different types) they can be coerced into one of these situations.
  • Every other comparison is considered unequal.

Identity

In JavaScript, the identity is tested using === and the counterpart !==. In contrast to the equality test, the identity variant does no type conversion, and the types must be the same to be considered equal.

var num = 42;
var str = "42";
alert(num === str); //prints "false" in an alert box

Lineup

While a test for equality provides great flexibility in terms of type mixing, it suffers from bad performance due to all the background work to be done. In contrast, the identity test executes way faster but doesn’t handle any type conversion at all.

As a rule of thumb, a developer should therefore pick identity- over equality-tests, if the expressions to be compared are of the same type.

Combined conditional evaluation

Like in any modern high level language, JavaScript also enables the composition of combined conditionals by using boolean operators. See the following snippet below:

if(firstCondition && secondCondition){ }

JavaScript is smart enough to abort the conditional evaluation if firstCondition returns false, so secondCondition will never be evaluated.

if(thirdCondition || fourthCondition){ }

As in the first example the result of the complete conditional is predictable as soon as thirdCondition evaluates true. In that case fourthCondition will never be tested.

This behaviour is often referred to as “short-circuit evaluation“. As a result, the execution of reduntant code might be omitted by clever use of conditional statements.

Using "self" for closures

To get access to the current context this inside a closure function you have to assign the context variable to a local variable. To keep your code clear and easier to manage it is recommended to use self as name for the local variable.

outer : function() {
  var self = this;
  closure : function()
  {
     // accessing the context with "self"
     self.anyMemberMethodCall();
  }
}

The variable name ‘‘self’ is also supported by the qooxdoo internationalization feature. See Internationalization for more information.

Information

Last modified:
2007/12/12 11:01 by wpbasti

Account

Not logged in

 
 

Job Offers

To further improve qooxdoo we are seeking javascript developers. Read more...

Rich Ajax Platform (RAP)

RAP uses qooxdoo, Java and the Eclipse development model to build rich web applications. Read more...

qooxdoo Web Toolkit (QWT)

Similar to GWT this framework allows to create impressive qooxdoo applications just using Java. Read more...

Pustefix

Pustefix is a MVC-based web application framework using Java and XML/XSLT. Read more...

 
SourceForge.net Logo

Bad Behavior has blocked 0 potential spam attempts in the last 7 days.