Disclaimer: Most of the items I am going to go through are very situation dependant.
Most are only worthwhile inside loops or heavily utilised code (~500,000 ops/sec). Please don't use these all over the place...
If you haven’t already heard of jsPerf, you need to check it out.
From the site: jsPerf aims to provide an easy way to create and share test cases, comparing the performance
of different JavaScript snippets by running benchmarks.
The Unary + (or -) Operator.
The unary + operator can be used to coerce all JavaScript types to a Number.
When used on types other than String, it will call valueOf() or toString() (in that order) and then attempt to convert the result to a Number.
The Complement (~) when used as a unary operator, first converts n to an Integer and then performs -(n+1)
For example:
var x = 123,
y = 456.789;
alert(~x); // -124
alert(~y); // -457
This provides a nice opportunity when dealing with functions that return sentinel values such as String.indexOf() or jQuery.inArray()
These functions return an index between 0 and N for success and -1 for a failure. This usually requires code to check the return value is >= 0
With our friend the ~ we can remove the need for some characters and gain a tiny little performance boost in Firefox.
jsPerf
BONUS: With all of the bitwise operators, any Number is converted to a 32 Integer before the operation takes place.
This means that a double tilde can also be used to floor a number. (If its positive).
There are also a couple of other ways to try and optimise flooring as can be seen from the jsPerf Tests.
Array.push
It should be no surprise that using objects directly rather than their convenience methods would be faster.
One place we can take advantage of this is Array manipulation.
Quite often a loop will be used to push a subset of objects into an Array.
For Example:
var x = [true, false, true, true, false, false, true],
y = [];
for (var i = 0; i < x.length; i++) {
if (x[i]) {
y.push(x[i]);
}
}
In highly optimised code, it can be more beneficial to just directly add the new item to the end of the array.
jsPerf
Flags and Bitmasks
Also referred to as Bit Twiddling.
Usually used in highly optimised code where memory usage is important.
These sorts of practices are common in C++, games programming, etc.
Not only is this method faster to execute, (jsPerf) but uses much less memory compared to using objects and properties to represent the same information.
Memoization
Memoization is a technique for caching the results of function calls to avoid additional computation.
And is probably the one performance technique from today you might use.
Memoization is however not appropriate if the method's output changes over time, is unlikely to be called again with the same parameters or the computation is actually faster that the added overhead.
There are a lot of Memoization implementations, however Addy Osmani (@addyosmani) has recently done a great write-up on the most performant implementation.
/*
* memoize.js
* by @philogb and @addyosmani
* with further optimizations by @mathias
* and @DmitryBaranovsk
* perf tests: http://bit.ly/q3zpG3
* Released under an MIT license.
*/
function memoize( fn ) {
return function () {
var args = Array.prototype.slice.call(arguments),
hash = "",
i = args.length;
currentArg = null;
while (i--) {
currentArg = args[i];
hash += (currentArg === Object(currentArg)) ?
JSON.stringify(currentArg) : currentArg;
fn.memoize || (fn.memoize = {});
}
return (hash in fn.memoize) ? fn.memoize[hash] :
fn.memoize[hash] = fn.apply(this, args);
};
}
It should be no surprise Memoizing functionality such as the Fibonacci sequence yields high performance gains.
jsPerf
Now for a contrived example!
Putting it all together.
var GetAirports = function(filter, credentials) {
var result = [],
i = 0;
// Check we are allowed to view airports
if (credentials.canViewAirports) {
// Check are allowed to search by Id and if an Id was entered
if (credentials.canSearchById && parseInt(filter)) {
return [airports[filter]];
}
filter = filter.toUpperCase();
// Search for the filter anywhere in either the code, name or location properties
for (i; i < airports.length; i++) {
if (airports[i].code.indexOf(filter) >= 0 ||
airports[i].name.toUpperCase().indexOf(filter) >= 0 ||
airports[i].location.toUpperCase().indexOf(filter) >= 0) {
// Add matches to the result
result.push(airports[i]);
}
}
return result;
}
};
Incremental implementation of bitwise changes. jsPerf.