32 JavaScript Programming Tips

Published:

1

Avoid defining the variables in the global scope; trying to define them in a local function scope. Because:
  • Look-up is performed every time a variable is accessed.
  • Variables are resolved backwards from most specific to least specific scope.
  • Any variable created without the var keyword is created at the global scope and is not
     garbage collected when the function returns (because it doesn’t go out of scope), presenting the
     opportunity for a memory leak. Therefore, use variables in the same scope whenever possible,
     and avoid global variables at all costs.

2

Use a global array, global object, or namespace prefix. If you need global variables, use a global object that contains all of the global variables, like this:
var myBulletinBoardAppGlobals = {
                          foo: "some value",
                          bar: null
                      };

Open in new window

Or consider using a namespace prefix (a.k.a., a special naming convention):
CPWFoo = "some value";
                      CPWBar = null;

Open in new window

These practices prevent your global variables from colliding with global DOM objects present in the runtime.

3

Use {} instead of new Object().
For instance:
var o = {         // better than var o= new Object; o.name= ... (etc.)
                         name: 'Jeffrey',
                         lastName = 'Way',
                         someFunction : function() {
                            console.log(this.name);
                         }
                      };
                      var o = {};

Open in new window

4

Use [] instead of new Array().
var a = ['Joe','Plumber'];  // better than var a= new Array()

Open in new window

5

Use The Unary + Operator To TypeConvert To Number
In JavaScript, the + operator is used for both addition and concatenation. This can cause problems when adding up form field values, for example, since JavaScript is a non-typed language.  Form field values will be treated as strings, and if you add them with +, JavaScript will treat it as concatenation instead of addition.

To fix this problem, JavaScript needs a hint to tell it to treat the values as numbers, rather than strings. You can use the unary + operator to convert the string value into a number.  Prefixing a variable or expression with + will force it to evaluate as a number, which can then be successfully used in a math operation.

Good Practice
function total() {
                          var theform = document.forms["myform"];
                          var total = (+theform.elements["val1"].value) + (+theform.elements["val2"].value);
                          alert(total); // This will alert 3
                      }

Open in new window

Not As Good
<form name="myform" action="[url]">
                      <input type="text" name="val1" value="1">
                      <input type="text" name="val2" value="2">
                      </form>
                      function total() {
                          var theform = document.forms["myform"];
                          var total = theform.elements["val1"].value + theform.elements["val2"].value;
                          alert(total); // This will alert "12", but what you wanted was 3!
                      }

Open in new window

6

To prevent unreachable code, a return, break, continue, or throw statement should be followed by a } or case or default.

7

Avoid the eval method, it effectively requires the browser to create an entirely new scripting environment, import all variables from the current scope, execute the script, collect the garbage, and export the variables back into the original environment. Additionally, the code cannot be cached for optimization purposes, and might be vulnerable to script injection attacks.

8

When using a typeof check, don't use the parenthesis for the typeof.

9

It is almost always better to use the = = = and != = operators. The = = and != operators do type coercion. In particular, do not use = = to compare against falsy values.

For Example:
'' = = '0'          // false
                      0 = = ''            // true
                      0 = = '0'           // true
                      false = = 'false'   // false
                      false = = '0'       // true
                      false = = undefined // false
                      false = = null      // false
                      null = = undefined  // true
                      
                      ' \t\r\n ' = = 0    // true

Open in new window

10. Always use a [i]radix[/i] parameter with parseInt

parseInt is a function that converts a string into an integer. It stops when it sees a nondigit, so parseInt("16") and parseInt("16 tons") produce the same result. It would be nice if the function somehow informed us about the extra text, but it doesn't.

If the first character of the string is 0, then the string is evaluated in base 8 instead of base 10. In base 8, 8 and 9 are not digits, so parseInt("08") and parseInt("09") produce 0 as their result. This error causes problems in programs that parse dates and times. Fortunately, parseInt can take a radix parameter, so that parseInt("08", 10) produces 8.

11. return Statement

A return statement with a value should not use ( ) (parentheses) around the value. The return value expression must start on the same line as the return keyword in order to avoid semicolon insertion.

12. continue Statement

Avoid use of the continue statement.  It tends to obscure the control flow of the function.

13. with Statement

The with statement should not be used

14. Post-load Components

You can take a closer look at your page and ask yourself: “What's absolutely required in order to render the page initially?”. The rest of the content and components can wait.

JavaScript is an ideal candidate for splitting before and after the onload event. For example if you have JavaScript code and libraries that do drag and drop and animations, those can wait, because dragging elements on the page comes after the initial rendering. Other places to look for candidates for post-loading include hidden content (content that appears after a user action) and images below the fold.

See: http://ajaxpatterns.org/On-Demand_Javascript

15. Preload Components

Preload may look like the opposite of post-load, but it actually has a different goal. By preloading components you can take advantage of the time the browser is idle and request components (like images, styles and scripts) you'll need in the future. This way when the user visits the next page, you could have most of the components already in the cache and your page will load much faster for the user.

16. Don't Pass a String to 'SetInterval' or 'SetTimeOut'

Consider the following code:
setInterval(
                      "document.getElementById('container').innerHTML += 'My new number: ' + i", 3000
                      );

Open in new window

Not only is this code inefficient, but it also functions in the same way as the "eval" function would. Never pass a string to SetInterval and SetTimeOut. Instead, pass a function name or the anonymous function.
setInterval(someFunction, 3000);

Open in new window

OR
setTimeout(function () {
                          // Code to execute on a timeout
                      }, 50);

Open in new window

17. Cache the result of expensive look-ups in local variables

Good Practice
var arr = ...;
                      var globalVar = 0;
                      (function () {
                          var i, l, localVar;
                          l = arr.length;
                          localVar = globalVar;
                          for (i = 0; i < l; i++) {
                              localVar++;
                          }
                          globalVar = localVar;
                      })();

Open in new window

Not As Good
var arr = ...;
                      var globalVar = 0;
                      (function () {
                          var i;
                          for (i = 0; i < arr.length; i++) {
                              globalVar++;
                          }
                      })();

Open in new window

18. Don’t use the RegExp constructor

Don’t use the RegExp constructor, unless your regular expression is assembled at runtime. Instead, use regular expression literals.

19

In regular expressions use the test method if all you want to do is test for a pattern (the exec method carries a small performance penalty).
if (/loaded|complete/.test(document.readyState)) {...}

Open in new window

20. Primitive operations are often faster than the corresponding function calls

Good Practice
var a = 1, b = 2, c;
                      c = a < b ? a : b;	var a = 1, b = 2, c;
                      c = Math.min(a, b);

Open in new window

Not As Good
var a = 1, b = 2, c;
                      c = Math.min(a, b);

Open in new window

Good Practice
myArray[myArray.length] = value;
                      myArray[idx++] = value;
                      myArray.push(value);

Open in new window

Not As Good
myArray.push(value);

Open in new window

21

Avoid using try...catch in performance-critical sections:
Good Practice
var i;
                      try {
                          for (i = 0; i < 100000; i++) {
                              ...
                          }
                      } catch (e) {
                          ...
                      }

Open in new window

Not As Good
var i;
                      for (i = 0; i < 100000; i++) {
                          try {
                              ...
                          } catch (e) {
                              ...
                          }
                      }

Open in new window

22. Avoid for…in in performance-critical sections

Good Practice
var i, value, length = myArray.length;
                      for (i = 0; i < length; i++) {
                          value = myArray[i];
                          ...
                      }

Open in new window

Not As Good
var key, value;
                      for (key in myArray) {
                          value = myArray[key];
                          ...
                      }

Open in new window

23

Branch outside, not inside, whenever the branching condition does not change.
Good Practice
var fn;
                      if (...) {
                          fn = function () {...};
                      } else {
                          fn = function () {...};
                      }

Open in new window

Not As Good
function fn () {
                          if (...) {
                              ...
                          } else {
                              ...
                          }
                      }

Open in new window

24. Minimize DOM Access

Accessing DOM elements with JavaScript is slow so in order to have a more responsive page, you should:
  •  Cache references to accessed elements
  •  Update nodes "offline" and then add them to the tree i.e. use display:none while adding then
     change it to display:block.
  •  Avoid fixing layout with JavaScript i.e. don’t change the styles through javaScript use the
     appropriate style classes.

25. Reduce the Number of DOM Elements

A complex webpage means more bytes to download and it also means slower DOM access in JavaScript.  It makes a difference if you loop through 500 or 5000 DOM elements on the page when you want to add an event handler for example.

The number of DOM elements is easy to test, just type in Firebug's console:
document.getElementsByTagName('*').length

Open in new window

26. Use of DocumentFragment

A DocumentFragment (DOM Level 1 Core) is a lightweight Document object.
It supports only a subset of the regular DOM methods and properties.
var i, j, el, table, tbody, row, cell, docFragment;
                      docFragment = document.createDocumentFragment();
                      el = document.createElement("div");
                      docFragment.appendChild(el);
                      table = document.createElement("table");
                      el.appendChild(table);
                      tbody = document.createElement("tbody");
                      table.appendChild(tbody);
                      for (i = 0; i < 1000; i++) {
                          ...
                      }
                      document.body.appendChild(docFragment);

Open in new window

27. Use of innerHTML

In case major modifications are required in document tree, use innerHTML
Good Practice
var i, j, el, idx, html;
                      idx = 0;
                      html = [];
                      html[idx++] = "<table>";
                      for (i = 0; i < 1000; i++) {
                          html[idx++] = "<tr>";
                          for (j = 0; j < 5; j++) {
                              html[idx++] = "<td></td>";
                          }
                          html[idx++] = "</tr>";
                      }
                      html[idx++] = "</table>";
                      el = document.createElement("div");
                      document.body.appendChild(el);
                      el.innerHTML = html.join("");

Open in new window

Not As Good
var i, j, el, table, tbody, row, cell;
                      el = document.createElement("div");
                      document.body.appendChild(el);
                      table = document.createElement("table");
                      el.appendChild(table);
                      tbody = document.createElement("tbody");
                      table.appendChild(tbody);
                      for (i = 0; i < 1000; i++) {
                          row = document.createElement("tr");
                          for (j = 0; j < 5; j++) {
                              cell = document.createElement("td");
                              row.appendChild(cell);
                          }
                          tbody.appendChild(row);
                      }

Open in new window

28. Use of cloneNode

In-case need to create same element in document tree again and again use the cloneNode instead of createElement:

Good Practice
var i, el, table, tbody, template, row, cell;
                      el = document.createElement("div");
                      document.body.appendChild(el);
                      table = document.createElement("table");
                      el.appendChild(table);
                      tbody = document.createElement("tbody");
                      table.appendChild(tbody);
                      template = document.createElement("tr");
                      for (i = 0; i < 5; i++) {
                          cell = document.createElement("td");
                          template.appendChild(cell);
                      }
                      for (i = 0; i < 1000; i++) {
                          row = template.cloneNode(true);
                          tbody.appendChild(row);
                      }

Open in new window

Not As Good
var i, j, el, table, tbody, row, cell;
                      el = document.createElement("div");
                      document.body.appendChild(el);
                      table = document.createElement("table");
                      el.appendChild(table);
                      tbody = document.createElement("tbody");
                      table.appendChild(tbody);
                      for (i = 0; i < 1000; i++) {
                          row = document.createElement("tr");
                          for (j = 0; j < 5; j++) {
                              cell = document.createElement("td");
                              row.appendChild(cell);
                          }
                          tbody.appendChild(row);
                      }

Open in new window

29. Use event delegation

Event delegation has several benefits to the performance of a web application:
   o Fewer functions to manage
   o Takes up less memory.
   o Fewer ties between your code and the DOM
   o Don't need to worry about removing event handlers when changing the DOM via innerHTML.

30. Use objects instead of literals when accessed often


Any properties and methods are defined on the string object, not the value. When you reference a property or method of a string value, the ECMAScript engine must implicitly create a new string object with the same value as your string, before running the method. This object is only used for that one request, and will be recreated next time you attempt to use a method of the string value.

If your code calls methods of literal values very often, you should consider converting them into objects instead, as in the previous example.

31. Avoid Recursion

JavaScript does not offer tail recursion optimization; therefore functions that recurs too deeply will eventually fail.

32. Optimize loops

Loops can become very slow if don’t do them right. One of the most common mistake is to read the length attribute of an array at every iteration. This means that every time the loop runs, JavaScript needs to read the length of the array. We can avoid that by storing the length value in a different variable:

Good Practice
var names = ['George','Ringo','Paul','John'];
                      var all = names.length;
                      for(var i=0;i<all;i++){
                        doSomeThingWith(names[i]);
                      }
                      ...OR...
                      var names = ['George','Ringo','Paul','John'];
                      for(var i=0,j=names.length;i<j;i++){
                        doSomeThingWith(names[i]);
                      }

Open in new window

Not As Good
var names = ['George','Ringo','Paul','John'];
                      for(var i=0;i<names.length;i++){
                        doSomeThingWith(names[i]);
                      }

Open in new window

[Editor's Note] These tips appear to have been compiled from numerous web sites.  Here is a partial listing:
    http://developer.yahoo.com/performance/rules.html
    http://www.slideshare.net/julien.lecomte/high-performance-ajax-applications
    http://javascript.crockford.com/code.html
    http://drupal.org/node/172169
1
4,087 Views

Comments (2)

CERTIFIED EXPERT
Author of the Year 2009

Commented:
There are a number of useful tips here.  Thanks for posting this.  However...

As a long-time JavaScript programmer, I'd like to say that I take issue with many of the tips above.   For most of them, there is no background or explanation as to why they should be used, and in fact, the "performance optimization" that can (or I really should say might under some circumstances) be obtained is often so trivial as to be not worth mentioning.

It is too bad that you did not provide documentation, benchmark timing tests, or other information that would be so helpful.  That would have made this a much better article.
iGottZd.3 Administrator
CERTIFIED EXPERT

Commented:
i support DanRollins comment. some of your listings just dont make sense.

why should i as example avoid recursion?
recursion can be even more performant in some cases if it is done right then you think.
have you ever tryed using call() or apply()?
sharing the same scope with theese methods would result in a single scope for a whole recursion.

also some of your code like 22 is not correct. why should i write with a loop into a -variable-?
your function there overrides the same variable on each loop run.

also your code example at 20 does not make sense. just look at it and you see what i mean.

your point 18 does not make sense because for the javascript core its no efford to convert that to a real expression.
if you mentioned this then why didnt you told us to remove all unneeded spacing and new lines? and specialy comments?


sorry but i just cant feel the love to javascript in your article.
you talk about scopes but do not even talk about prototypes.

Have a question about something in this article? You can receive help directly from the article author. Sign up for a free trial to get started.