Standardista

CSS3, JavaScript and HTML5 explained

16 Common JavaScript Gotchas

We all know that JavaScript can trip you up. Here are a 16 common traps that can trip you up when coding javascript. You likely know most of the code on the page, but if you keep these 16 gotchas in your mind, coding and debugging will be less of a headache:

  1. Case sensitivity: Variable names, properties and methods are all case sensitive
  2. Mismatching quotes, parenthesis or curly braces will throw an error
  3. Conditional Statments:3 common gotchas
  4. Line breaks: Always end statements in semi-colons to avoid common line break issues
  5. Punctuation:Trailing commas in object declarations will trip you up
  6. HTML id conflicts
  7. Variable Scope: global versus local scope
  8. string replace function isn’t global
  9. parseInt should include two arguments
  10. ‘this’ and binding issues
  11. Function overloading: Overwriting functions, as overloading doesn’t exist
  12. Setting default values for parameters in case you omit them
  13. For each loops are for objects, not arrays
  14. switch statements are a little tricky
  15. Always check for Undefined before checking for null
  16. Function location may matter
Case Sensitivity
Variables and function names are case sensitive. Like mismatched quotes, you already know this. But, since the error may be silent, here is the reminder. Pick a naming convention for yourself, and stick with it. And, remember that native javascript function and CSS properties in javascript are camelCase.

getElementById('myId') != getElementByID('myId'); // it should be "Id" not "ID"
getElementById('myId') != getElementById('myID'); // "Id" again does not equal"ID"
document.getElementById('myId').style.Color; // returns "undefined"
Mismatching quotes, parenthesis and curly brace
The best way to avoid falling into the trap of mismatched quotes, parentheses and curly brackets is to always code your opening and closing element at the same time, then step into the element to add your code. Start with:

var myString = ""; //code the quotes before entering your string value
function myFunction(){
     if(){   //close out every bracket when you open one.

	 }
}

//count all the left parens and right parens and make sure they're equal
alert(parseInt(var1)*(parseInt(var2)+parseInt(var3))); //close every parenthesis when a parenthesis is open

Every time you open an element, close it. Put the arguments for a function into the parenthesis after you’ve added the closing parenthesis. If you have a bunch of parenthesis, count the opening parenthesis and then the closing parenthesis, and make sure those two numbers are equal.

Conditional statements (3 gotchas)
  1. All conditional comments must be within parentheses (duh!)
    if(var1 == var2){}
  2. Don’t get tripped up by accidentally using the assignment operator: assigning your second argument’s value to your first argument. Since it’s a logic issue, it will always return true and won’t throw an error.
    if(var1 = var2){} // returns true. Assigns var2 to var1
  3. Javascript is loosely typed, except in switch statements. JavaScript is NOT loosely typed when it comes to case comparisons.
    var myVar = 5;
    if(myVar == '5'){ // returns true since Javascript is loosely typed
      alert("hi");  //this alert will show since JS doesn't usually care about data type.
    }
    switch(myVar){
      case '5':
      alert("hi"); // this alert will not show since the data types don't match
    }
Line Breaks
  • Beware of hard line breaks in JavaScript. Line breaks are interpreted as line-ending semicolons. Even in a string,if you include a hard line break in between quotes you’ll get a parse error (unterminated string).
        var bad  = '<ul id="myId">
                       <li>some text</li>
                       <li>more text</li>
                    </ul>'; // unterminated string error
    
        var good = '<ul id="myId">' +
                       '<li>some text</li>' +
                       '<li>more text</li>' +
                   '</ul>'; //correct
  • The line break being interpreted as a semi-colon rule, discussed above, does not hold true in the case of control structures: line breaks after the closing parenthesis of a conditional statement is NOT given a semi-colon.

Always use semi-colons and parenthesis so you don’t get tripped up by breaking lines, so your code is easier to read, and, less thought of but a source of quirks for those who don’t use semicolons: so when you move code around and end up with two statements on one line, you don’t have to worry that your first statement is correctly closed.

Extra commas
The last property in any JavaScript object definition must never end with a comma. Firefox won’t barf on the trailing, unnecessary commas, but IE will.

HTML id conflicts
The JavaScript DOM bindings allow indexing by HTML id. Functions and properties share the same namespace in JavaScript. So, when an id in your HTML has the same name as one of your functions or properties, you can get logic errors that are hard to track down. While this is more of a CSS best practice issue, it’s important to remember when you can’t solve your javascript issue.

var listitems = document.getElementsByTagName('li');

var liCount = listitems.length; // if you have <li id="length">, returns that <li> instead of a count.

If you’re marking up (X)HTML, never use a javascript method or property name as the value for an ID. And, when you’re coding the javascript, avoid giving variables names that are ID values in the (X)HTML.

variable scope
Many problems in javascript come from variable scope: either thinking that a local variable is global, or overwriting a global variable unwittingly with what should be a local variable in a function. To avoid issues, it’s best to basically not have any global variables. But, if you have a bunch, you should know the “gotchas”.

Variables that are not declared with the var keyword are global. Remember to declare variables with the var keyterm to keep variables from having global scope. In this example, a variable that is declared within a function has global scope because the var ke

anonymousFuntion1 = function(){
	globalvar = 'global scope'; // globally declared because "var" is missing.
	return localvar;
}();

alert(globalvar); // alerts 'global scope' because variable within the function is declared globally

anonymousFuntion2 = function(){
	var localvar = 'local scope'; //locally declared with "var"
	return localvar;
}();

alert(localvar); // error "localvar is not defined". there is no globally defined localvar

Variable names that are introduced as parameter names are local to the function. There is no conflict if your parameter name is also the name of a global variable as the parameter variable has local scope. If you want to change the global variable from within a function that has a parameter duplicating the global variable’s name, remember that global variables are properties of the window object.

var myscope = "global";

function showScope(myscope){
  return myscope; // local scope even though there is a global var with same name
}
alert(showScope('local'));

function globalScope(myscope){
  myscope = window.myscope; // global scope
  return myscope;
}
alert(globalScope('local'));

You should even declare variables within loops

for(var i = 0; i < myarray.length; i++){}
string replace
A common mistake is assuming the behavior of the string replace method will impact all possible matches. Infact, the javascript string replace method only changes the first occurrence. To replace all occurrences, you need to set the global modifier.

  var myString = "this is my string";
  myString = myString.replace(/ /,"%20"); // "this%20is my string"
  myString = myString.replace(/ /g,"%20"); // "this%20is%20my%20string"
parseInt
The most common error with parding integers in javascript is the assumption that parseInt returns the integer to base 10. Don’t forget the second argument, the radix or base, which can be anything from 2 to 36. To ensure you don’t screw up, always include the second parameter.

parseInt('09/10/08'); //0parseInt('09/10/08',10); //9, which is most likely what you want from a date.
‘this’
Another common mistake is forgetting to use ‘this‘. Functions defined on a JavaScript object accessing properties on that JavaScript object and failing to use the ‘this’ reference identifier. For example, the following is incorrect:

function myFunction() {
  var myObject = {
     objProperty: "some text",
     objMethod: function() {
		alert(objProperty);
		}
     };
  myObject.objMethod();
} 

function myFunction() {
  var myObject = {
     objProperty: "some text",
     objMethod: function() {
		alert(this.objProperty);
		}
     };
  myObject.objMethod();
}

There’s an A List Apart article that puts this binding issue into plain English

Overwriting functions / overloading functions
When you declare a function more than once, the last declaration of that function will overwrite all previous version of that function throwing no errors or warnings. This is different from other programming languages, like java, where you can have multiple functions with the same name as long as they take different arguments: called function overloading. There is no overloading in javascript. This makes it vitally important to not use the names of core javascript functions in your code. Also, beware of including multiple javascript files, as an included script may overwrite a function in another script. Use anonymous functions and namespaces.

(function(){
	// creation of my namespace
    // if namespace doesn't exist, create it.	if(!window.MYNAMESPACE) {		window['MYNAMESPACE'] = {}; 		}

    // this function only accessible within the anonymous function
    function myFunction(var1, var2){
		//local function code goes here
    }

    /* attaches the local function to the namespace
       making it accessible outside of the anoymous function with use of namespace */
    window['MYNAMESPACE']['myFunction'] = myFunction; 

 })();// the parenthesis = immediate execution	  // parenthesis encompassing all the code make the function anonymous
Missing Parameters
A common error is forgetting to update all the function calls when you add a parameter to a function. If you need to add a parameter to handle a special case call in your function that you’ve already been calling, set a default value for that parameter in your function, just in case you missed updating one of the calls in one of your scripts.

function addressFunction(address, city, state, country){
      country = country || "US"; // if country is not passed, assume USA
      //rest of code
    }

You can also get the length of the argument array. But we’re focusing on “gotchas” in this post.

For each
The “for” loop in javascript will iterate it over all object attributes, both methods and properties, looping thru all of the property names in an object. The enumeration will include all of the properties—including functions and prototype properties that you might not be interested in—so filter out the values you don’t want using hasOwnProperty method and typeof to exclude functions. Never use for each to iterate thru an array: only use for each when needing to iterated thru object properties and methods.

  • for each (var myVar in myObject) iterates a specified variable over all values of object’s properties.
  • for (var myVar in myObject) iterates a specified variable over all the properties of an object, in arbitrary order. The for...in loop does not iterate over built-in properties. For each distinct property the code is executed
  • for (var 1=0; i < myArray.length; i++) iterates thru all the elements of an array.

To fix the problem, generally you’ll want to opt for for ... in for objects and use the for loop for arrays:

listItems = document.getElementsByTagName('li');

for each (var listitem in listItems){
    // this goes thru all the properties and methods of the object,
    // including native methods and properties, but doesn't go thru the array: throws error!
   }

//since you have an array of objects that you are looping thru, use the for loop
for ( var i = 0; i < listItems.length; i++) {
    // this is what you really wanted
   }
Switch statements
I wrote a whole blog post on switch statement quirks, but the gist is:

  • there is no data type conversion
  • once there is a match, all expressions will be executed until the next break or return statement is executed, and
  • you can include multiple cases for a single block of code
Undefined ≠ null
Null is for an object, undefined is for a property, method or variable. To be null, your object has to be defined. If your object is not defined, and you test to see whether it’s null, since it’s not defined, it can’t test, and will throw an error.

if(myObject !== null  && typeof(myObject) !== 'undefined') {
	//if myObject is undefined, it can't test for null, and will throw an error
}

if(typeof(myObject) !== 'undefined' && myObject !== null) {
	//code handling myObject
}

Harish Mallipeddi has an explanation of undefined versus null

Function location can matter
There are two ways to declare function: When declaring a function in the form of a variable assignment, location does matter:

var myFunction = function(arg1, arg2){
  // do something here
};

A function declared with

function myFunction (arg1, arg2){}

can by used by any code in the file no matter its location (before or after the function declaration). A function declared with the variable assignment syntax can only be used by code that executes after the assignment statement that declares the function.

2 Responses to “16 Common JavaScript Gotchas”

  1. Estelle Weyl says:

    Thing to remember: Two HTML attribute names are reserved words in JavaScript: use element.className for the class attribute element.htmlFor for the for attribute

  2. Xavier B says:

    Thanks for these ‘gotchas’. (don’t know exactly how to translate it because I’m french)
    There is one more I’ve been thinking about reading this great article :
    When using the style property, don’t forget to replace the dash ‘-’ (used by core javascript as an operator of subtraction) of style properties by nothing followed by uppercase letter :
    Examples :

    -> document.getElementById(‘someID’).style.backgroundImage = ‘url(“img.jpg”)’;
    -> document.getElementById(‘someID’).style.fontSize = ’10px’;

Leave a Reply