Although this isn't a problem in other languages, because of semicolon insertion, there could be problems if you don't place the bracket on the opening line:
// no:
function()
{
return // semicolon inserted here by the engine. Returns null (not {})
{
}
}
// yes:
function() { // this semicolon placement doesn't matter, but we should be consistent
return {
}
}
JavaScript natives are camelCased, so we should be consistent.
Javascript native Object constructors are Capitalized, so we should be consistent.
Check for the existence of a feature before using it:
// no:
navigator.connection;
// yes:
if(navigator.connection) {
navigator.connection;
}
If you're going to reuse the feature test, make sure to run it once and cache the result (as Modernizr does). This speeds things up and makes things easier to maintain in the future.
// no:
if(navigator.connection) {}
if(navigator.connection) {}
// yes:
var connection = navigator.connection;
if(connection) {};
if(connection) {};
Unless it's a polyfill, generally don't modify objects you didn't create. I.e. Object.prototype
// no:
var foo = document.getElementsByTagName('p');
for(var i=0; i<foo.length; i++) {}; // hitting the DOM on each iteration
// yes:
var foo = document.getElementsByTagName('p');
for(var i=0, len=foo.length; i<len; i++) {}; // hits the DOM only once
Use for/while instead, as it's faster.
Check if a callback is defined and is executable before trying to run it:
// no:
function(callback) {
callback();
};
// yes:
function(callback) {
if(callback && typeof callback == 'function') callback();
};
// also yes:
function(callback) {
callback && typeof callback == 'function' && callback();
};
If you don't know if a variable is defined:
// no:
foo; // don't use it before checking if it exists
if(foo); // if foo isn't defined, it will create a Reference Error
if(foo === undefined) {} // the undefined variable can be overwritten, so avoid it
// yes:
if(typeof foo == 'undefined');
if(window.foo) {} // if foo is a property of another object (in this case the global window)
function(foo) {
if(foo){}; // ok because foo has been defined in the arguments
}
Triple equals saves a lot of headaches, but you can use == when the possible output doesn't have truthy/falsy problems. For instance, the typeof operator:
if(typeof foo == 'undefined') {}
// no:
(function(){})();
// yes:
(function myFunc(){})();
(note that this is buggy in < IE8)
// change this:
function() {
if(foo) {
fn1();
} else {
fn2();
}
}
// to this:
function() {
if(foo) {
fn1();
return;
}
fn2();
}
Use shorthand at your own discretion, but clarity should be valued over brevity. Anyhow, rely on the minifier to make your code short.
Try to make your variable names semantic and descriptive. Don't make them too short or too long (at your discretion).
// no:
var a = ''; // not descriptive
var getNumberOfSkinCareEligibleItemsWithinTransaction = function() {}; // too long
// yes:
var tag = '';
var eligibleItems = function() {};
for(var i=0; i<10; i++) {}; // variable 'i' is ok because it's a common convention
TODO
// this:
if(somethingExists && fn && typeof fn == 'function') {
fn();
};
// is equivalent to this:
somethingExists && fn && typeof fn == 'function' && fn();
// this:
if(fn1) {
fn1();
} else {
fn2();
}
// is equivalent to this:
fn1() || fn2();
// this:
function Person(options) {}
var me = new Person;
// is equivalent to this:
function Person(options) {
if(!this || this === window) return new Person(options);
}
var me = Person;
See John Resig: Best Practices in Javascript Library Design http://www.youtube.com/watch?v=0LKDImgRfrg#t=32m2s. Above code modified to support ECMAScript 5 strict mode (!this, as strict mode sets 'this' to null and not window by default).
great tips 👍