JavaScript 

Best Practices



Om Shankar

-- Likes the Web and believes moving it forward

-- Doesn't know much, but never fails to speak !

-- Have written Articles for magazines and blogs

-- Built awesome HTML5 Apps in Webkit at Adobe

-- Built performance driven modern client-side and web at Amazon

-- Building a Next-gen collaboration system with WebRTC and Node

-- Loves HTML5 and CSS3

Press right arrow key. When bottom arrow glows, you can press down arrow key

Introduction

Browser

-- Is a collection of 3 Layers 
-- They are and should be essentially ordered as I am gonna say..

JavaScript

-- forms the Behavior Layer
-- all the interactions and things that a Human can do
-- clicking, scrolling, typing, submitting a form, dragging stuff, moving the mouse out of curiosity, etc.

Explained at a blog ...

Browser Layers

Clicking on the image takes you there !

Beginner Level

Loading

-- Put Scripts at the bottom of the page, make external for caching, etc.
-- Try a JavaScript loader and download scripts parallely, or when required
For eg., this slideshow itself uses HeadJS
-- Minify scripts when loading on production. Join them to resuce HTTP requests
Coding

-- Use === to test Equality
-- Start functions and returns on the same line with the {
-- Do not use eval() and setTimeOut, setInterval, etc. for executing code
-- Do not use try catch in a loop

Examples

              
"5" == 5; // true
"5" === 5 ; // false
var a = 5; eval("a = 6"); setTimeOut("a = 5", 200); // bad

/** Performance  ***/

// very bad if you need such code
var object = ['foo', 'bar'], i;
for (i = 0; i < object.length; i++) {
  try {
    // do something that throws an exception
  } catch (e) {
    // handle exception
  }
}

// look for a purpopseful refactoring:
try {
  for (i = 0; i < object.length; i++) {
    // do something
  }
} catch (e) {
  // handle exception
}
              
            

Intermediate Level

- Declare Variables outside of loops statement but inside of functions
- Maximize object resolution speed and minimize scope chain
- Take care with multiplications on floats, JavaScript is not for Rocket Science
- Use comma separated expressions to merge multiple var declarations
- Use Literals - avoid new Constructors for Objects, Arrays, Numbers, Strings.
- Alternative primitive ways are faster than helper functions and APIs

- An expression is "true" if so is its return value. Same for "false"!
- Only false values are 0, an empty string, null, undefined and false itself
- Check for return values and Truthiness / Falsiness of expressions
- Complex functions can be cached and used in a loop locally, for speed
- Objects are different than Arrays
- There is nothing called else if in JavaScript, theoretically at least
- There is nothing called Associative Arrays in JavaScript - they are Objects

Examples - 2.1

              
/** Since local variables are first in the chain, they’re always faster than globals **/
function LocalScope(doc) {
  // assuming doc was passed as window.document
  var blah = doc.getElementById('myID'), 
      blah2 = doc.getElementById('myID2'); // instead of document.getElementById
}

/** Maximize object resolution speed and minimize scope chain **/
var url = location.href; /* slower than */ var url = window.location.href;

// Disclaimer - Webkit and other engines optimize this beautifully

/** Literals and Constructors **/

var super = new Number(5); // -- constructor way
super * 2; // 10, so its a number
typeof super; // "object"
super.someProperty = "Man of Steel"; // Works.

var bat = 5;
// bat has almost all the properties that super does. Both are Numbers
typeof bat; // "number" !! 
bat * 10; // 50
// However, JavaScript abstracts the constructor and makes bat read-only
bat.someProperty = "can use Super powers"; // doesn't work - read only
              
            

Examples - 2.2

              
var hamburger = 8.20, 
    fries = 2.10,
    total = hamburger + fries;
console.log(total); // Outputs 10.299999999999999

hamburger = hamburger * 100, fries = fries * 100, total = hamburger + fries;
total = total / 100; // Outputs 10.3

/** Alternative primitive/native ways are faster than helper functions and APIs **/
var min = Math.min(a, b);
arr.push(val);
// faster
var min = a < b ? a : b;
arr[arr.length] = val;

/** Complex functions can be cached and used in a loop locally **/
var d=35, y = 0;
for (var i=0; i<1000; i++) { 
  y += Math.sin(d)*10;
} // Accessing Math Obj and then its "sin" method in a loop is slower

var d = 55, y = 0, math_sind = Math.sin(d)*10;
for (var i=0; i<1000; i++) {
  y += math_sind; 
}
              
            

Examples - 2.3

              
/** If Else **/
if (condition) {
  // walk
} else if (condition2) {
  // dance 
} else {
  // sing
}
// Above is same as:
if (condition) {
  // walk
} else {
  if (condition2) {
    // dance 
  } else {
    // sing
  }
}

/** Truthiness && !Falsiness **/

2 || "hello world" || 0 || false || -1 || undefined; 
// A true expression
// When we use || to join, the return value is first true or last false value (if all false)

               
            

Examples - 2.4

              
5 && true && undefined && true && "Hello world" && 10.2; 
// False expression when using &&
// Return value is first false or last true (if all true). 
// Hence, the value of above is undefined

/** ! Associative arrays **/

abc = {
  0: 1, 
  someProperty: false,
  10: "Some Random String",
  true: 42
}
abc.someProperty; // false
abc['someProperty']; // false, but this does not make it associative array
// When we use square brackets [], the content inside is evaluated

// [] are for that purpose alone (not associativity, huh)
var number = 10;
abc[number]; // "Some Random String" , notice the absence of quotes around number
abc[ 1 > 0 ]; // 42, Surprise !

              
            

Advanced Level

- Take care of Memory hoisting
- Memoization - Optimize function for dynamic programming
- Optimize DOM manipulation code to avoid Reflows
- Avoid for-in in performance-critical functions
- Understand Callbacks and Asynchronous programming
- Use SingleTon constructors when you want only one instance throughout
- Use call and apply for functions to change their context effectively
- Use hasOwnProperty to check if the property is Object's own

Examples - 3.1

              
/** Memory Hoisitng - pulling of declarations and definitions at top **/
alert(abc);
var abc = 'some string';
// is same as:
var abc;
alert(abc);
abc = 'some string'; // And thats why you do get an "alert", but it says "undefined"

/** Hoisting inside scopes is exclusive to the scope **/
var n = 1;
function printSomething() {
    console.log(n);
    var n = 2;
    console.log(n);
}
printSomething();
// undefined
// 2

// its due to hoisting that this works
abc();
function abc() { ... }
// But this doesn't
abc();
var abc = function() { ... }  // TypeError: undefined is not a function
              
            

Examples - 3.2

              
/** Memoization **/
// caching the return value of the function for already calculated values of n
var fibonacci = (function() {
  var memo = {};
  function f(n) {
    var value;
    if (n in memo) {
      value = memo[n];
    } else {
      if (n === 0 || n === 1)
        value = n;
      else
        value = f(n - 1) + f(n - 2);
      memo[n] = value;
    }
    return value;
  }
  return f;
})();
              
            

Examples - 3.3

              
var mySingleton = (function () {
  var instance;
  function init() {
    var privateVariable = "Im a private";
    var privateRandomNumber = Math.random();
    return {
      publicMethod: function () {
        console.log( "The public can see me!" );
      },
      publicProperty: "I am also public"
    };
  };
  return {
    getInstance: function () {
      if ( !instance ) {
        instance = init();
      }
      return instance;
    }
  };
})();

var instanceOne = mySingleton.getInstance(), 
    instanceTwo = mySingleton.getInstance();
instanceOne.publicMethod(); // is same as calling instanceTwo.publicMethod()
            
          

Super Level

Start loving JavaScript, explore, innovate, enlighten!
Follow and then Lead

People and Links

-- Addy Osmani, my fav guy 1 on JS - Learning JS Design Patterns
-- Nicholas C Zakas, my fav guy 2 on JS - Speed up your JavaScript
-- Stoyan Stefanov, my fav guy 3 on JS - OO JavaScript
-- Dev.Opera.com - Efficient JavaScript
-- JavaScript Performance comparisons - JS Perf & Example
-- Google Developers - Minimizing Browser Reflow
-- Google Developers - Optimizing JavaScript code
-- My blog (least updated) - Objects Constructors & Property Checking
-- Lint your code - JS Lint

Happy JavaScript-ing,

Om Shankar
JavaScript & HTML5 Guy - Adobe Systems.