JavaScript Mistakes You Must Avoid

Share


If you are new to JavaScript and you write raw JavaScript or use any framework (jQuery, Mootools, Dojo, YUI) with it, you must avoid few mistakes. Actually these are my experiences when I was learning JavaScript.

Equality Operator

You may know that in js, two operators are used for comparing values. First is == (two equal signs). This operator compare the values but it doesn’t compare the data type of operands. For example if first operand is 1 and the second is true, the result will be true.

if( 1 == true ) {
    //this code will run
}

Here are more examples.

1 == "1"        //true
"true" == true  //false
1 == true       //true
"0" == 0        //true
"" == 0         //true
" " == 0        //true
"Str" == false  //false
"Str" == true   //false

Some of the results are unexpected specially for those who don’t know how JavaScript evaluates == operator. Actually every operand (no matter what data type it has) is converted to Number data type before comparison.

Consider the first example (1 == “1″). The first operand is already a number so no conversion occurs. Second operator is string so it’s converted or parsed to number. Now the second operator “1″ (string) is converted to 1 (number).

In the second example (“true” == true) is false because if the string contain characters other than digits, convertion to number will return NaN which means Not a Number. If anything is compared with NaN, comparison will always return false.

You can check what value will be returned after conversion to number using the Number constructor. Following are some tests in Firebug.

Number tests

Now you maybe wondering how === operator works. Equality operator (with 3 equal signs) in JavaScript compare not only the value of operands, but also the data type. If the data type of operands is different, it will always return false. Both the data type and value of operands must be same in order to make the condition true.

4 === 4         //true
"2" === 2       //false
1 === true       //false
"true" === true //false

Not Assigning null to Reference Types

It’s common mistake that many js developers don’t assign null value to variables of reference types (object or Array) when there use is finished. Take a look at following example.

var arr = [1, 2, 3];
 
//perform some processing on arr
 
//assign null to arr when its use is finished
arr = null;

The benefit of assigning null to reference types is that the garbage collector of js engine automatically reclaims the memory used by that variable. Remember that this is specially important for variables whose scope is large like global variables. Local variables are automatically destructed when they are out of scope (specially js engines with Mark and Sweep garbage collector).

Reference Variable Initialization

Never try to initialize multiple reference variables (like object and array) in a single assignment statement. This can be better understood using an example.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var arr1 = [1, 2, 3]
  , arr2 = ['a', 'b', 'c'];
 
//reset both arrays
arr1 = arr2 = [];
 
//add a single item in arr2 and arr1
arr2.push( 32 );
arr1.push( 10 );
 
//print both arrays and you will see same result
//OUTPUT: 10, 32
alert( arr1.join() );
alert( arr2.join() );

On line 1 and 2, two arrays are created. Then those arrays are reinitialized with blank array in a single statement on line 5. The problem with this statement is that now both arrays (arr1, arr2) are pointing to same array in the memory. So changes in one will automatically be reflected in the other.

On line 8, integer 32 is added in arr2 and on line 9, integer 10 is added in arr1. To check the output of both arrays, join method is called on each of them on lines 13 and 14. Note that both arrays contain same values.

Don’t Forget Keyword var

In JavaScript you can declare variables with keyword var. But it also allows you to use variables without any declaration. There’s a very critical difference between these two ways of using variables. Consider the following example.

function createVar() {
	var myVar = 'local';
};
 
alert( myVar ); //output: undefined

As you can see from the above example when a variable is declared with keyword var, it’s not accessible in the outer scope. Let’s change this example to define a variable without var in function.

function createVar() {
	myVar = 'local';
};
 
alert( myVar ); //output: local

Note that a variable defined without keyword var in function is also accessible from the global scope. In other words var makes the variable local. So becareful when using variables in JavaScript. Always declare your variables using keyword var before using them.

Not Using Event Delegation

Attaching event handler is simple in JavaScript. For example following code adds a click handler to anchor tag having id myLink.

document.getElementById('myLink').addEventListener( 'click', function() {
   //you code goes here...
}, false );

Now suppose you want to add a click handler to all the td elements in table. Are you going to write a handler for each td in table?

<table id="myTable">
   <tbody>
      <tr>
         <td>1, 1</td>
	 <td>1, 2</td>
      </tr>
 
      <tr>
         <td>2, 1</td>
	 <td>2, 2</td>
      </tr>
   </tbody>
</table>

Here event delegates help us. In our case we will attach a single click event handler to myTable and within that we will check to see if a td element is clicked or not. In this way we don’t have to write and attach event handlers to every td in table. Such kind of handler is known as event delegate. Here’s the code for it.

document.getElementById( 'myTable' ).addEventListener( 'click', function( e ) {
      if( e.target && e.target.nodeName == 'TD' ) {
         console.log( e.target.innerHTML );
 
         //to access id
         //console.log( e.target.id );
 
         //to access className
         //console.log( e.target.className );
      }
   }, false );

innerText VS innerHTML

New js developers are often confused between innerHTML and innerText properties. Both innerHTML and innerText are used with element objects. innerHTML gets the html code inside the element and innerText gets the text inside the element.

innerHTML working

The dark gray background in Html is actually the output of innerHTML property. Note that the Html tags (in our case <p>) are also included in the output.

Let’s take a look at innerText example.

innerText working

As you can see from the above example that innerText gets the text inside the element (without html tags).

Adding Nodes in Bulk

It’s common in JavaScript to append list of nodes to some element in DOM. For example you may want to append a list of names to ul received from server using Ajax call. One way of doing this is shown below.

window.onload = function() {
//ul element - <ul id="list"></ul>
var list = document.getElementById( 'list' );
 
var item = null;
 
//suppose this json is returned from ajax call
var ajaxResponse = [
    { 'name' : 'Haiku' },
    { 'name' : 'Linux' },
    { 'name' : 'OS X' },
    { 'name' : 'Windows' }
];
 
//add all names in ajaxReponse to documentFragment
for( var i in ajaxResponse ) {
    item = document.createElement( 'li' );
    item.appendChild( document.createTextNode( ajaxResponse[ i ].name ) );
    list.appendChild( item );
}
} //end onload
 
/*
..:: OUTPUT ::..
<ul id="list">
<li>Haiku</li>
<li>Linux</li>
<li>OS X</li>
<li>Windows</li>
</ul>
*/

The problem with this method is that each time the item is appended to list in "for in" loop, the DOM gets updated immediately. This hurts performance because DOM manipulation is costly process.

“DocumentFragment is light weight version of document and it has no visual representation on the web page.”

The same output can be achieved using DocumentFragment. DocumentFragment is light weight version of document and it has no visual representation on the web page. Following is the example to append list items using DocumentFragment.

window.onload = function() {
    //create DocumentFragment
    var documentFragment = document.createDocumentFragment();
 
    var list = document.getElementById( 'list' ); //<ul id="list"></ul>
    var item = null;
 
    //suppose this json is returned from ajax call
    var ajaxResponse = [
	{ 'name' : 'Haiku' },
	{ 'name' : 'Linux' },
	{ 'name' : 'OS X' },
	{ 'name' : 'Windows' }
    ];
 
    //add all names in ajaxReponse to documentFragment
    for( var i in ajaxResponse ) {
	item = document.createElement( 'li' );
	item.appendChild( document.createTextNode( ajaxResponse[ i ].name ) );
	documentFragment.appendChild( item );
    }
 
    //append all items in documentFragment to list
    list.appendChild( documentFragment );
}

John Resig wrote an excellent post explaining DocumentFragment and its impact on performance.

DOM Manipulation using innerHTML

Never use arithmetic assignment operator (+=) with innerHTML to add new markup. Whenever you change innerHTML, DOM updation occurs (Browser redraws the markup). So adding new markup using += operator (specially in a loop) decreases performance.

var container = document.getElementById( 'container' );
 
for( var i = 1; i <= 10; ++i ) {
    container.innerHTML += 'Item ' + i + '<br />';
}

Always use a temporary variable to store the markup you want to assign to innerHTML as shown below.

var container = document.getElementById( 'container' )
  , str = '';
 
for( var i = 1; i <= 10; ++i ) {
    str += 'Item ' + i + '<br />';
}
 
container.innerHTML += str;
This entry was posted in Blog, JavaScript. Bookmark the permalink.

46 Responses to JavaScript Mistakes You Must Avoid

  1. tom says:

    great! thank you for that informative post.

    Tom

  2. rob d says:

    Great Post! I learned many good points!

  3. Andres Descalzo says:

    in the example of “innerText” you “innerHTML”. thank you for that informative post.

  4. Rodger says:

    FYI: Your “innerText” example calls “innerHTML” again. Probably just a cut-n-paste error. No need to include this comment.

  5. PCTip says:

    Thanks for this post. I like the way you handle DOM elements and event delegation. That are really useful tips.

  6. Paul says:

    Two quick notes.

    First, it’s better to delete arr; rather the set it to null. Three reasons for this: its more obvious what you are doing, the GC knows at that moment that the var can be collected, and null is a data type which slows the parser down during static analysis. But you are absolutely right that you want that old array marked for clean up.

    Second, not all browsers have innerText. There is a way to do this with feature detection, but I can’t remember it off hand. (Also, there is a typo in the code for innerText. It uses innerHTML.)

    • iFadey says:

      Thanks for tip Paul.

      Second: Yes you are right. Not all browsers support innerText. Like Firefox use textContent instead of innerText

      Typo is fixed now.

  7. Vinny says:

    Hey, nice article; totally using doc fragments now, much more streamlined.

    Also, for innerText vs innerHTML are they both suppose to be the same code?

  8. IainB says:

    The innerText image has .innerHTML() in the javascript section… should be innerText()

  9. Christopher says:

    Good article! Special thanks for explaining the “Equality Operator” :)

  10. Jigar Shah says:

    Can you suggest a good (small :) ) book which can help me to clear basic js concepts ?

  11. Garrett says:

    “First, it’s better to delete arr; rather the set it to null. Three reasons for this:”

    Here’s one reason not to do it: It doesn’t work.

    Check the result of that operation.

    (function(){
      var arr = [1,2,3]
      alert(delete arr); // false
      alert(arr);
    }());
    

    Kangax article explains it.
    http://perfectionkills.com/understanding-delete

    And BTW, An array is not a reference type; a “Reference”, as defined in ES3, consists of a base object and the property name. In the example above, the base object of `arr` is is what is called an Activation Object in ES3.

  12. Adelar says:

    Great article :D

  13. EJ Frias says:

    Very informative article..

    Btw, just saw a typo (the 1 == true //false) on

    4 === 4 //true
    “2″ === 2 //false
    1 == true //false
    “true” === true //false

    Cheers ^_^

  14. Thanks a lot man, really instructive, I will surely keep this in my bookmarks.

  15. Sandeep says:

    Good and exhaustive list

  16. Ian says:

    for…in? That’s no good. Tip #1 should be never to use for…in, it’s the slowest possible loop.

    http://jsperf.com/custom-for-loop-vs-regular-for-loop/6

    • Marc Qualie says:

      That would be true if it were for Array types, but the data type was Object. Since Object types don’t have a length property, and normally won’t have integers as keys, a normal for loop can’t be used.

  17. Pingback: Javascript Mistakes You Must Avoid « Clear Illusion

  18. Great article, good techniques and some stuff I didn’t know, especially the stuff about explicit garbage collection by setting reference types to null. Thanks!

  19. Pingback: Webprogrammierung & Design » Blog Archive » JavaScript Tutorial: JavaScript einbinden – http://www.html-seminar.de

  20. Pingback: jQuery Weekly Roundup #4: 5/11/11 - webdesigncrowd.com

  21. Filip says:

    in the “Don’t Forget Keyword var” part, I think you really need to stress that not defining variables with the var keywords and hence putting them in the global scope is a very bad thing. Firstly these variables are visible to everything, secondly, when referencing the variable in your code, it takes longer to get to it as you have to go through all the scopes in the hierarchy.
    It should also be mentioned that variable scope in JavaScript is delimited by a function declaration not by block. Since function can also contain other functions, variables defined in the top level function are visible to all the contained functions as well, but then we start getting into closures… probably another post, hey?

  22. Alexander Trefz says:

    “So adding new markup using += operator (specially in a loop) decreases performance.” And in the “Good-Example” below you used it yourself. Its not the Operator, it is the same error as with DocumentFragment, “Avoid multiple Reflows for actions that could be done with one reflow”.

  23. mwilcox says:

    One of the better articles on JS mistakes. Congrats!

    You don’t point out that Firefox does not support innerText. It uses textContent. And innerText != textContent.

    http://clubajax.org/plain-text-vs-innertext-vs-textcontent/

  24. Pingback: jQuery, Railscasts, Mobile Applications, & More | Tom McFarlin

  25. Jake Verbaten says:

    As is already mentioned “innerText” is not supported by all browsers.

    The problem with this is that “textContent” is the standard way to manipulate text as set by the W3C standards.

    “innerText” is an IE only function that’s not in the standard. It’s like recommending you use “attachEvent” or htc files.

    For future reference please do not spread examples with IE only proprietary code.

  26. Pingback: Link-urile săptămânii 9-15 mai | Staicu Ionuţ-Bogdan

  27. alemarko says:

    Great article, you should just correct one bit:

    >> Actually every operand (no matter what data type it has) is converted to Number data type before comparison.

    Definitely not true, because strings comparisons would not work.

    “abc” == “def” // false
    “abc” == “abc” // true -> you say it would be false, same as Nan == Nan

    Also, maybe to warn readers about result of following comparison and teach/remind them what for function ‘isNaN()’ is used:

    Nan == Nan // false
    isNaN(2) // false
    isNan(Nan) // true

    Regards,
    Alex

  28. Pingback: Linkhub – Woche 19-2011 | PehBehBeh

  29. Uhh you have one problem. All browsers don’t support innertext, still ):. Great post though.

  30. Ryan Gasparini says:

    The Event portion will not work for IE users. addEventListener is the W3C version, “e” (a.k.a. MouseEvent) is not provided to event functions (is window.event), and target is actually srcElement.

  31. David says:

    Great article. I liked the part about document fragment. I never heard about that. Is this implemented consistently among major browsers?

  32. Colm Britton says:

    Hi,

    Excellent article, I found it very useful. Although I do have one point to make. I’m not sure your first tip about the == operator is 100% correct. If all strings are converted to Numbers and returned as NaN then no 2 strings would match;
    NaN == NaN always returns false
    however
    if you compare 2 identical strings true will be returned
    “test” == “test” will return true
    but according to your explanation “test” would be converted to NaN so the comparison would become
    NaN == NaN
    and as I said earlier this returns false.

    Hope that helps.

  33. iFadey says:

    I think must have mentioned this point. If both operands are strings, then they are not converted to number for comparison. That’s why it’s returning true.

    If a number is compared with string, the string is converted to Number. If any non numeric value is stored in string, then it returns NaN. Any operand compared with NaN will always return false.

    This happens with == (double equal) operator

  34. Pascal says:

    Really great article!
    I knew some parts of it already but especially the null assignment for garbage collection is something good to know :D

  35. Junior says:

    I think you should learn a bit more about the language before going out giving “advice” on the internets. Assigning to null is only necessary if your variable is eating a lot of memory AND it’s being kept in a closure that will be kept. Garbage collection exists precisely so you don’t need to manage memory manually.

    • Senior says:

      Maybe you should learn a bit more about spelling before posting derogatory posts on the *internets*. If you had left out your first sentence your point would not have been lost as it is at present.

  36. Great informative post, plenty of tips for beginners and some old gotcha’s for professionals to watch out for. One minor nitpick: can you replace all instances of the word ‘specially’ with ‘especially’ in your post?

    :P

    James

  37. Thanks for the post, its good to read pure JS articles rather than a JS framework.

  38. Nice post. I consider most of the examples/statements made to be common knowledge, but after reading the comments, I guess it’s not. But it’s nice to see some of the mistakes we all made when we first started tinkering with JS. :-)

    For other stuff in this post I usually use jQuery, which really does most of the heavy lifting, in the most effective way. But it makes you lazy, which is a bad thing I guess.

    Never heard (or read) about createDocumentFragment(). It’s nice to learn some new stuff once in a while!

    Thanks,

    Michiel

  39. Pingback: HTML5, CSS, Javascript useful links « 달달한 바람같이