Common JavaScript Mistakes


Syntax: Having an additional trailing comma

In Prototype-style classes, we often write our code in this fashion:

var Rectangle = Class.create({
	initialize: function() {
		// Do something
	},
	fooize: function(a,b) {
		return a * b
	// ERROR
	},
})
FireFox will not complain, but IE and Safari will break

Semantic: Forgetting to declare a variable

Many JavaScript programmmers forget to explicitely declare variables by using the var keyword. The variable gets declared in the global scope, and the variable can be modified anytime by another function which uses the same unprefixed variable.

var Utility = {
	getSize: function(x1, y1, x2, y2) {
		size = [x2-x1, y2-y1];
		return size;
	}
};

var Rectangle = Class.create({
	initialize: function(x,y,w,h) {
		size = [w, h];
		boundingBox = Utility.getSize(x-5, y-5, x + w+5, y + h+5);
		// ERROR
		this.size = size;
	}
});

var r = new Rectangle(10,10,100,100);
alert("Rectangle.size is " + r.size.toSource());
In Rectangle.initialize size is now [110,110] instead of [100,100]

Semantic: Not preserving this when giving a method as callback

Callbacks are heavily used in JavaScript, and when doing OO programmming in JavaScript, we often have to give methods as callbacks for event handling or AJAX. The problem is that the original context of the method (the instance) is not preserved, so that the callback will be executed in the caller context.

var Widget = Class.create({
	initialize:function(){
		this.clicks = 0;
	},
	onClick: function() {
		this.clicks += 1;
	}
});

var widget = new Widget();
// ERROR
$(".counter.button").bind("click", widget.onClick);
$(".counter.button").bind("click", function(){alert("Clicks: " + widget.clicks)});
The widget.onClick attribute will never be modified, instead the callback caller will have its 'clicks' slot modified (with unpredictable side-effects)

Semantic: Looping over an array slots instead of its elements

The for( var x in ...) JavaScript statement can be quite confusing, because it does not behave as Python or Ruby programmmers would expect. The for( var x in ...) actually iterates over an object slots. Arrays being objects, not only will you get indices of array elements instead of the elements themselves, but you will have the name of any additional slot defined in the array.

var a = ['a', 'b', 'c'];
// We add a custom slot
a.elementsCount = 3;
var r = "";
for ( k in a ) {
	r += "value:" + k + " ";
};
alert("Result: " + r);
The expected result would be [a, b, c], but we have instead [0,1,2,elementsCount]

Semantic: Closures definition in for loops

Scoping rules in JavaScript are sometimes a bit strange. Most of the time creating a closure will take a snapshot of its environment, but in some cases, it just don't.

function f(selector) {
	var inputs = $(selector);
	for ( var i=0 ; i<inputs.length ; i++ ) {
		// ERROR
		var input = inputs[i];
		$(input).bind("click", function(){
			alert("Input " + $(input).attr("name") + " was clicked");
		})
	}
};
f("input.button");
If we have two buttons named A and B, then clicking on A or B will always print 'B', because when a closure references a variable declared in a for loop, only the last assignment of the value in the loop will be used for creating the closure.