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.
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.
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.
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 );
}
|
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;