Link: JavaScript Semicolon Insertion 1
Read a really good post on automatic semicolon insertion (ASI) in JavaScript. I highly recommend reading it if you’re not familiar with how ASI works.
http://inimino.org/~inimino/blog/javascript_semicolons
The author even includes the parser expression grammar for ECMAScript for those interested.
Enjoy!
JavaScript Anti-Patterns
There are plenty of posts discussing anti-patterns in other languages, like Java or Python. However, I haven’t really seen much regarding JavaScript besides this question on StackOverflow. And most of the ones I found don’t separate the DOM API and the JavaScript language itself.
So the following is a list of JavaScript anti-patterns that I’ve compiled, with some explanations.
Polluting the global namespace
This is the biggest no-no, and is something all new JavaScript developers must learn. The reason you don’t want to declare too many variables in the global namespace is the avoid conflicts with code written by others or yourself. Here’s an example to illustrate this:
function foo() { return 1; }
function bar() { for (i=0; i<5; i++) {} }
i = foo();
bar();
// what is i here?
In this example, i=5 at the end of execution. This happens because the variable i both inside and outside the function left out the var declaration, thus the engine declares it in the global namespace. And if everyone’s code rely on global variables, you may break someone else’s code accidentally.
Extending the Object prototype
Never, never, never extend Object.prototype. By doing that you could break a lot of code that do things such as for (var a in myObj) – such as jQuery. That is the very reason why Crockford’s jslint promotes the use of hasOwnProperty() check. But IMO that produces ugly code. The better way is to just leave Object.prototype alone.
Using multiple var declarations instead of one
In each scope you can make multiple variable declarations by separating each one with a comma. This makes code more readable, and performs better too (albeit by a very small margin).
// Don't do this
function foo() {
var x = 1;
var y = 2;
var z = 3;
}
// Do this
function foo() {
var x = 1,
y = 2,
z = 3;
}
Using new Array() and new Object()
Please don’t declare arrays and hashes like this.
var arr = new Array(),
hash = new Object();
hash.a = 1;
hash.b = 2;
When you do this instead.
var arr = [],
hash = { a: 1, b: 2 };
Not making use of truthy/falsey values: undefined, null, false, ”, [], etc.
In JavaScript, a variable’s value can be truthy or falsey. This mean that while the value isn’t strictly equivalent to the boolean values true and false, they can be coerced into a boolean value.
// No need for this! if (someString != undefined && someString != '') alert(someString); // This gives the same result and is much cleaner if (!someString) alert(someString);
You can run quick tests in your browser to check if something is truthy or falsey.
var a; // undefined
if (!a) alert('falsey');
if (!'') alert('falsey');
if ([1,2]) alert('truthy');
if (!null) alert('falsey');
if (!0) alert('falsey');
if (100) alert('truthy');
Not making use of truthy/falsey values (part 2): for loops
Another great use of truthy and falsey is in a for loop. In most other languages, the exit-check of the loop usually makes sure the index does not go out of bounds. But in JavaScript we can do one better!
// an array of lower-case letters
var arr = ['a', 'b', ..., 'z'];
// don't do this
for (var i=0; i<arr.length; i++) {
// do something with arr[i]
}
// do this
for (var i=0, curr; curr=arr[i]; i++) {
// do something with curr
}
The second for loop works because arr[i] is undefined if i is an out-of-bounds index, and undefined is falsey. Also, this method performs better (especially in IE 6/7 where arr.length lookup can be costly). Be careful not to use this approach if you know an array may contain a zero (0), or any other falsey values you don’t want to prematurely exit from.
Using switch statements
A lot of times when you use a switch statement in JavaScript, you really should be using anonymous functions. This is because switch statements in JavaScript don’t perform as well as you’re probably used to in other languages.
// you may want to do this
function foo(x) {
var a;
switch (x) {
case 0:
a = 'foo';
break;
case 1:
a = 'bar';
break;
case 2:
a = 'faz';
}
return a;
}
// but you should do this instead
// Note: some anonymous function magic here...
// but it's pretty much same as above!
(function(scope) {
var handlers = [
function() { return 'foo'; },
function() { return 'bar'; },
function() { return 'faz'; }
];
scope.foo = function(x) {
return handlers[x]();
};
})(this);
This method can always be used when you want to switch on a string by using an hash instead of an array.
NB: there are times when a switch statement is appropriate, or even necessary. Control flow similar to Duff’s device, for example, needs the switch statement. Also, sometimes you don’t need to worry about performance too much, and may think switch statements are clearer. I rarely use them though.
Using a with block
Please, never use a with block to create a scope, unless you want really bad performance. Besides, you can achieve the same thing with anonymous functions without giving up performance. (learn to love anonymous functions !!)
// bad
with ({a: 1}) {
alert(a);
}
// good
(function(scope) {
alert(a);
})({a: 1});
Not making use of truthy/falsey values (part 3): Converting a value using Boolean(x)
Okay, I’m not sure if this counts a an anti-pattern but it’s more of a personal preference. Of course we should never use Boolean('') inside an if-check, but sometimes we want to convert any value into an actual boolean. What you should do instead of using Boolean(x) is to use !!x. This works because !x returns true if x is falsey, and false otherwise. We then negate that boolean again to get what we want.
Using for-in loop over an array
Arrays in JavaScript are special objects, so a for-in loop doesn’t do what you think it does.
var arr = ['foo', bar', 'faz', baz']'
for (var item in arr) {
// what is item here?
}
You may think you’ll get the values of the array above, but you actually get the indices inside the array. It’s easier just to stick to normal for loops.
JavaScript Namespacing
One of the first things you learn programming in JavaScript is, "Global variables are evil." This is especially true when writing a JavaScript library, but I’d take that advise even otherwise to avoid unnecessary headaches.
As an avid jQuery user, one thing I do in almost every project is define a namespace function on the jQuery object.
jQuery.namespace = function(ns, obj) {
var ns = ns.split('.'),
p = window,
i;
for(i=0; i<ns.length; i++)
p = p[ns[i]] = p[ns[i]] || {};
if (obj)
jQuery.extend(p, jQuery.isFunction(obj) ? obj(p) : obj);
};
This function will take in either an object or a function that takes in an object, then create the namespace or extend it if it exists.
// Example 1
$.namespace('foo.bar', {
myVar: 1, myOtherVar: 2, someFunction: function() { alert(this.myVar + ',' + this.myOtherVar); }
});
foo.bar.someFunction();
//--> alerts "1,2"
// Example 2
$.namespace('faz', { baz: { a: 1, b: 2 } });
$.namespace('faz.baz', function(old /* previous namespace */) {
old.a = 'new value'; // change previous assignment of a
old.printMe = function() { alert(old.a + ',' + old.b); };
});
faz.baz.printMe();
//--> alerts "new value,2"
The second example shows a case where an function is passed instead of an object. This is useful for many reasons which I won’t get into… actually you can read a great post here about JavaScript module patterns.
And when jQuery isn’t being used on a project, the following does the exact same.
function namespace(ns, obj) {
var ns = ns.split('.'),
p = window,
i, k;
for(i=0; i<ns.length; i++)
p = p[ns[i]] = p[ns[i]] || {};
if (obj) {
obj = obj instanceof Function ? obj(p) : obj;
for (k in obj) {
if (obj.hasOwnProperty(k))
p[k] = obj[k];
}
}
}
Reserved JavaScript Words in Safari
I ran into a problem today where the RIA I’m building works for all browsers except Safari – specifically Safari 4, not sure about 3.
The error happens when a certain page loads, and all I’m greeted with in Safar is `SyntaxError: Parser Error`. Nice.
After a little debugging and Googling, I realized that one of the objects I had setup used a property that was a JavaScript reserved word. For whatever reason, SquirrelFish (Safari 4’s JS engine) was the only engine to throw this error.
So something like this would work in all browsers except Safari:
// Parse Error in Safari 4
var myObject = {
enum: 1,
class: 'foobar',
faz: 'baz'
};
Instead, you need to wrap reserved words around quotation marks.
// Works in Safari 4 now
var myObject = {
'enum': 1,
'class': 'foobar',
faz: 'baz'
};
I’m not sure if SquirrelFish is correct, or the other engines. The inconsistency is a bit annoying though.
Not all jQuery selectors are created equal 2
The good thing about JavaScript libraries such as jQuery is that developers can focus on functionality without having to worry too much about cross-browser compatibility. However, often times it is still very useful to know why happens behind the abstractions.
The most used feature in jQuery is the CSS selector. Instead of selecting elements using pure DOM (e.g. document.getElementById(‘myId’)), you’re able to use jQuery’s CSS selector (e.g. $(‘#myId’)). This makes life much, much easier.
There are cases, however, where not knowing what happens behind the scenes can lead to poor implementations, causing big performance hits. One such case is the class selector (e.g. $(‘.someClass’)).
The reason why class selector is slow is because it has to go through the entire DOM to find those elements. Of course, some browsers like Firefox 3+ has native support for document.getElementsByClassName. And as John Resig analyzed, the native method is much faster than the next fastest implementation (XPath). But if you want your applications to run as fast as possible on as many browsers as possible, it’s better to avoid the class selector all-together (at least for now).
What you can do instead is to use the next fastest selector (behind ID selector), the tag name selector.
So instead of doing $(‘.someClass’), use $(‘div.someClass’), or whichever HTML tag name you want to use. This selector is faster because instead of checking the entire DOM, now it only needs to check against elements with that particular tag name. That is, it first does a document.getElementsByTagName(‘div’), then iterates through that list.
Or why not make it even faster by specifying an ancestor element by its ID? (e.g. $(‘#ancestor div.someClass’))
The thing to keep in mind is, no matter what abstractions come about, it’s still a very good idea to understand what happens underneath the hood. :)
JavaScript: Optimizing loops
When looping through very large arrays, you may find this tip useful: it’s much fast to use a while loop to iterate through an array than a for loop.
For example, if you take this code:
var myArray = new Array(10000);
for (var i=0; i<myArray.length; i++) {
myArray[i] = i;
}
You can make it run faster by using a while loop instead.
var myArray = new Array(10000);
var n = myArray.length;
while (n--) {
myArray[n] = n;
}
This works because n-- will return the value of n and then decrement it. So when it approaches index zero, it’ll coerce 1 to true, then decrement n before the line myArray[n] = n;.
Of course, this while-loop is looping backwards, so if the order of iteration does matter then you can’t use this method. You could however, still optimize the first example by first assigning myArray.length to a variable, then using that in the for-loop’s exit condition. This will make it run slightly faster (depending on which browser you’re using) because it avoids a property lookup at every loop iteration.
var myArray = new Array(10000);
var n = myArray.length;
for (var i=0; i<n; i++) {
myArray[i] = i;
}
Cheating on Speed Sudoku -- How to Prevent Greasemonkey Scripts
I recently read about Speed Sudoku in a Globe and Mail article. It’s a website that allows player to compete against each other in a race to solve Sudoku puzzles. Players are given points based on their performance in a game – I’m unsure how the point system works – and these points are used to rank them on the scoreboard. As of this writing, the top player is named "WaterlooMathie" (woot for Waterloo).
Anyway. I decided to write a Greasemonkey script to automatically solve these puzzles. The technique I chose is a simple Backtracking algorithm with cells chosen based on the Most Restrained Variable. *Disclaimer: I’m not planning on climbing to the top of the scoreboard using this script, it’s just for fun.
Nothing too fancy. In fact, the code can be tuned further to perform better – meh. But the results are pretty good. I’m able to solve the Very Hard puzzles on my Mac instantly on page load.
Even though I’m not going to cheat on Speed Sudoku, I’m sure others will, or already have. In fact, you can report users you suspect of cheating to the site admins.
This raises a question for me: How do you prevent Greasemonkey scripts from executing on your website?
The answer lies with how Greasemonkey scripts are fired – it listens to the DomContentLoaded event. To script execution you simply put this piece of code at the top of your page.
document.addEventListener("DOMContentLoaded", function(ev) {
ev.stopPropagation();
}, false);
This will attach your anonymous function to the same event listener (which will execute first), and we simply need to stop the event from propagating.
You might run into cases where you do want your own functions (attached to DOMContentLoaded event) to fire. In these cases, you could create your own custom events, listen on those, and fire them in the anonymous function after.
Of course, users can still cheat by other means, but at least this can prevent Greasemonkey cheats. That said, I’m against prevent Greasemonkey scripts. I love the addon, and it adds functionality to websites that I can’t live without.
Not Another IE6 Rant
For the last few months I’ve seen some aggressive campaigning to rid the online world of Internet Explorer 6. Many web developers and designers have been supporting this browser for what seems like forever, and now that IE6 is losing market shares fast, it seems like a good time to make the final push to kill it.
While I whole-heartedly agree that we’ll all be better off without IE6, I don’t agree with providing zero support for the browser. Let’s face it, the whole "browser X is outdated" thing isn’t new and will always be here to haunt us – remember Netscape 4?
I don’t mind providing users with a nice message about why they should upgrade their browsers, as long as it doesn’t obstruct workflow, and they need to have an option to never be bugged again. But please, please do not do something stupid like the #ie6update script. It’s wrong on many levels, and there is a good post on why it’s wrong.
The best way to approach older browsers, I think, is to use to use graceful degradation (older concept) or progressive enhancement (better). With the latter approach, you design your website for the lowest common denominator and progressively enhance it to improve user experience for newer, more advanced browsers. Of course, while PE sounds nice in theory, it does require a fair amount of discipline in practice.
And let’s not forget that there are JavaScript libraries out there to help developers cope with IE6, and even IE7. The defacto IE6/7 library is ie7-js, which adds support for many CSS selectors that are lacking in IE6/7, as well as many other nice things.
There is also a JS library for detecting different browsers and operating systems. While I don’t personally like this approach, it may be cleaner than writing a lot of IE CSS hacks. Maybe.
Video manipulation in Firefox 3.1 using HTML 5
Here’s an cool post from the Mozilla Developer Center regarding the new in Firefox 3.1. The demo featured is a video filmed with a green screen, and the green screen is replaced with an image in real-time using JavaScript.
Pretty neat stuff.
JavaScript, Anonymous Function, Closure, and You
There are many things that web developers should know about JavaScript, but the most basic of things are anonymous functions and closure. Both are very powerful tools for anyone working with JavaScript.
So what’s so great about them you ask? Well, I think that’s best explained using some examples.
Let’s say we want to implement a function that will take an integer representing a month, and return it’s name as a string.
e.g. 1 -> ‘January’, 2 –> ‘February’, 9 –> ‘September’
We’ll start out with a naive implementation, but perhaps one that first comes to mind.
function monthName(i) {
var months = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
];
return months[i-1];
}
Simple right? But there’s something wrong with this function. Take a look at the array declaration, it’s inside the function! That means everytime you call the monthsName function, it’ll create an array. This not only slows down your function, but it uses an unnecessary amount of memory.
Our first improvement then, would be to move the array to the outside of the function.
var months = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
];
function monthName(i) {
return months[i-1];
}
Great, now we only create array once! But wait, there’s another problem. We’ve just moved the months array into the global namespace. This is bad because we might be overwriting a previously declared variable also named months. Similarly, someone later on might overwrite our months array. D’oh!
Fortunately, there is a way around this. And this is where anonymous functions and closure come in. Let me show you the solution first.
var monthName = function() {
var months = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December'
];
return function(i) {
return months[i-1];
};
}();
So how does this work?
First, you’ll notice the block of code inside the outter function is similar to our second solution, except that the function name has been dropped, and it is now the return value of the outter function. The outter function is executed immediately, and is assigned to the variable monthName. Thus monthsName is really the inner function. Sort of.
Here is where closure comes in. The inner function refers to the months array declared outside of it, but because of closure, that array is bound to the function. So when we call the function monthName we are really calling the returned result of an anonymous function (which itself is an anonymous function). And this returned function has the months array bound to it.
Here’s another example using anonymous functions and closure to implement Partial Application in Javascript.
Function.prototype.papply= function() {
var fixed = Array.prototype.slice.call(arguments),
fn = this;
return function() {
return fn.apply(this, fixed.concat(Array.prototype.slice.call(arguments)));
};
}
Of course, you can probably achieve everything I’ve shown here without anonymous functions or closure, but why make it hard for yourself? Learn these tools, use them to your advantage!
Hello Interweb! 1
This is my first attempt at a dedicated programming blog. More interesting posts are on their way, but for now here’s a little info about me!
In my short professional career (which includes several co-op jobs when I attended the University of Waterloo) I’ve mostly been in web development. Actually, I’ve been doing the whole web stuff since about mid-90s, starting with HTML, JavaScript and Perl. Just on my personal/hobby websites.
I’ve worked with many languages, but my current interests are JavaScript and Python. I am a huge fan of Django, and have used it on several projects, including GlobeCampus. I expect the majority of my posts in the near-future to be on JavaScript and Python. ;)
Currently, I’m working as a web developer at The Globe and Mail.
