39

I'm planing on giving an introduction talk on JavaScript and in the preparation process I wondered what the top pitfalls are that rookies fall into.

I know I've had a few gotchas before I fully understood closure, but much of the strange behavior in JavaScript is not something I think about any more...

So, which pitfalls should you definitely point out to the rookies?

4

13 Answers 13

36

Boolean type conversion.

''        ==   '0'           //false
0         ==   ''            //true
0         ==   '0'           //true
false     ==   'false'       //false
false     ==   '0'           //true
false     ==   undefined     //false
false     ==   null          //false
null      ==   undefined     //true
" \t\r\n" ==   0             //true

As well as the difference between null and undefined. As listed in the table above, comparing null & undefined with == returns true, but with === it returns false. This behavior makes sense once you understand that undefined is very different from a variable having a null value, and something holding the value undefined is different from something being undefined.

Sign up to request clarification or add additional context in comments.

Comments

29

Don't accidentally leave a trailing comma in an object definition literal or IE will fail and you won't notice until much later because you never use IE for development and by then it could suck figuring out what happened.

var foo = { 
    bar: "bar", 
    baz: "baz", 
};

Note @JulianR's comment: In arrays, IE doesn't fail directly by throwing some syntax error, but will fail when you try to use the array because the added comma makes IE think there's one more element in the array, with value undefined, than there actually is. So if you ever have an error because for some reason the last element in an array is undefined: it's a comma.

2 Comments

+1 Very recognizable this one. In arrays, IE doesn't fail directly by throwing some syntax error, but will fail when you try to use the array because the added comma makes IE think there's one more element in the array, with value undefined, than there actually is. So if you ever have an error because for some reason the last element in an array is undefined: it's a comma.
+1 Excellent comment, this is a very nasty pitfall.
23

Admittedly I've been guilty of some of these in the past, for your amusement it's the ones in bold:

  • Not knowing incorrect (and the very few correct) uses of eval
    eval("obj."+prop);
  • Using with statements
  • Using parseInt(str, base) without specifying the base argument.
  • Using this in timer/callback functions.
  • Using eval-like expressions in timers
    setTimeout("someFunc(myScopedVarWhoops)");
  • Thinking jQuery is the name of the language you're coding
  • Performing simple JavaScript tasks using a framework -- $(1).plus(1) anyone? ;-)
  • Using continue without incrementing or adjusting the conditional variable.
  • Flooding the global namespace with variables
  • Forgetting var in or before for statements. for (i=0;i<10;i++)
  • Using an obfuscator and just letting it run wild on your code
  • Not really a pitfall, but pointless - return condition ? true : false; instead of return condition;
  • Not commenting your code, applies to all languages really.
  • Using try...catch...finally statements to catch errors instead of using if statements to check variables.
  • Foolishly attempting to stop "view source" by blocking right mouse clicks on your pages (I was young *sobs*!)
  • Using { 0: "Foo", 1:"Bar", 2:"Foobar" } instead of [ "Foo", "Bar", "Foobar" ]
  • Using parseInt() on user input
    parseInt("1,000") // -> 1, wrong!
    +"1,000" // -> NaN, correct!

Some already mentioned:

  • Not using strict equality (===) operators whenever possible
  • Setting event handlers to the return value of a function instead of a reference to said function
  • Not ; terminating statements properly
  • Using for...in loops on arrays

Might think of some more after I've slept :-)

14 Comments

Why shouldn't you use this in callbacks?
@Lèse: because callback functions, particularly ones used with timers, don't normally have a context.
@Andy E: What if you're assigning a callback to an event listener?
@Lèse: naturally, those are the exceptions, though they are referred to more as event listeners or event handlers than callback functions (even though they are callback functions). The confusion often stems from using this inside an event listener function, a lot of people think that this remains the same for functions defined in the same scope.
These links I found might clarify some of the other pitfalls for those unfamiliar with them: xkr.us/js/eval and dev.opera.com/articles/view/efficient-javascript/?page=2
|
15
  • Forgetting to declare variables with var
  • Misunderstanding (or not understanding) variable scope and closures
  • Trying to solve nasty compatibility problems that framework teams have already solved

2 Comments

Definitely the frameworks. By all means, someone should understand JS before using one. But they should know they're there.
Yeah, frameworks can be a big pitfall. This site is stuffed with questions from newbies trying to do something specific with jQuery. jQuery has a function that almost does the task, or do some of the task, but it is just too automagic to be more generally useful.
14

+ to concatenate strings:

var a = '2';
var b = 3;

a * b #  6
a - b # -1
a + b #  23

3 Comments

I agree with you. So many times I had to write something like a * 1 + b * 1 to do the trick or parse them to int. It's ridiculous.
this would also work +(a) + b #5
@Fuex - +a+ +b is shorter.
9

JavaScript strings are not byte strings, nor are they even Unicode strings. They are UTF-16 strings. Most characters, including international ones, are a single element in a JavaScript string. But some characters (including most emojis) fall outside the Basic Multilingual Plane and thus appear as two elements in a JavaScript string.

Example:

> "♫".length
1
> "𐌈".length
2
> "𐌈".charAt(0)
"\uD800"
> "𐌈".charAt(1)
"\uDF08"
> "𐌈" === "\uD800\uDF08"
true

4 Comments

Just to nitpick: there's nothing wrong with having UTF-16 strings, what's wrong is having leaky abstractions (like Javascript, .NET, Java, etc.etc.) an example of a sane Text API backed by UTF-16 is Haskell's Data.Text: (T.length $ T.pack "𐌈") == 1 returns True
UTF-16 is a way to encode unicode. So yes, they are unicode strings.
@berdario: cough utf8everywhere.org cough ^^
I rejected the edit to change "Unicode strings" to "UTF-8 strings". What I'm pointing out here is that a JavaScript string is not a sequence of Unicode codepoints. Each "array element" is a UTF-16 codepoint, meaning a surrogate pair is represented as two "characters" instead of one.
7

The biggest difficulties I see for the beginner are understanding execution context (i.e., what "this" means whenever and wherever it is encountered) and the prototype system of inheritance.

Comments

5
  • Closures - otherwise known as lambda functions - watch out for memory leaks.
  • Browser differences, testing in both Internet Explorer and at least one other browser is a must. Functions that only work in some browsers, or work differently in different browsers should generally be avoided. If this is not possible browser specific branching is better done detecting browser features instead of browser versions. This increases the chance of the code working in future browsers and browsers that have not been tested.
  • Getting too caught up in jQuery or Ajax framework abstraction, and not knowing the underlining JavaScript well enough to know how to fix framework issues.
  • Not knowing that JavaScript can be used to some degree to write OOP code. In fact it can give you a very basic OOP framework with objects.
  • Case sensitivity (if you're a VB.NET developer)
  • IP protection - knowing that you can obfuscate JavaScript, but the source code you put out there will be very easy to steal and reverse engineer. This might not even be an issue depending on the complexity of the client-side application you're writing.

I can't think of any more, but I hope this helps.

11 Comments

Browser detection is evil. You should use feature detection, not browser detection.
@el.pescado: +1, but to be fair, sometimes you need to detect behavior, which isn't as easy as detecting features and objects.
"Closures - otherwise known as lambda functions...". Not true - closures can be lambdas, but don't have to be (they can also be named functions).
@el.pescado: Browser detection isn't evil, it's merely ineffective and error-prone.
To address the comments about browser vs feature detection: This isn't incredibly hard to do. jQuery provides very good support for handling this (api.jquery.com/jQuery.support). If you don't want to use jQuery, I would still recommend checking out the jQuery.support source code as it's very easy to implement on your own as needed. (github.com/jquery/jquery/blob/master/src/support.js)
|
4
  • Using window.onload = init(); instead of window.onload = init;
  • Boolean equivalences (as mentioned already)
  • Closures within a loop.
  • Using for in loop variant for iterating over Arrays.
  • Not using ; because it's "optional".
  • this (just... in general :))
  • Not using var
  • Knowing that obj.ref === obj["ref"]

Comments

4
  • Creating sites that don't work without JavaScript
  • Using JavaScript for things that should be done server-side
  • Using frameworks for simple tasks that don't require them

Comments

3

The whole concept of prototyping takes some time to fully understand but here are some common pitfalls:

Forgetting to reset the constructor property after assigning a prototype object:

var Foo() = function ()
{
    this.batz = '...';
};
Foo.prototype = new Bar();
Foo.prototype.constructor = Foo;

If you forget the least line, new Foo() will actually execute Bar().

Another pitfall with prototyping is iterating over objects/arrays without filtering out the members of the prototype:

for (var i in obj) {
    if (obj.hasOwnProperty(i)) {
        //stuff...
    }
}

The extra condition will skip any members that are inherited from the prototype of obj.

Comments

3

Not a real coding pitfall, but more one of general thought:
Don't trust the things your JavaScript is doing, it might have been turned off or even monkey patched. That means never rely on client-side validation. NEVER.

Comments

2
typeof null is object


>>> var i = 1 + undefined; i;
NaN
>>> var i = 1 + null; i;
1

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.