
Common JavaScript Gotchas - stevekwan
https://github.com/stevekwan/best-practices/blob/master/javascript/gotchas.md
======
FuzzyDunlop
Javascript is probably an excellent example of something written without any
consideration of how it would work at scale (which is exactly what we tend to
promote). The idea of it suddenly being used for writing single page
applications and entire UIs, and now servers and god knows what else, was
probably unthinkable at the time.

It wasn't that long ago when all JS did was put snowflakes on a page, or
trails of fire behind your cursor, or annoying sequences of alerts and
prompts. And it was called DHTML.

Were it possible - in the 90s - to anticipate the recent surge in popularity
of JS, maybe we would have had a totally different language.

That said, these 'gotchas' are just part of learning the language. Same with
PHP really. With a sufficient level of experience you tend to forget they
actually exist.

~~~
Mahn
The sad part is that there is little effort into changing this. Javascript was
clearly not designed for what is being used nowadays, but browsers vendors
don't believe in introducing a new client language because apparently it's
hard to get everyone to agree to a new standard client language. I wonder if
the people behind W3C ever considered discussing this. Those gotchas in the
article above are not really a tremedous hassle once you learn to live with
them, but nonetheless while working on the client side one is still left
wanting more from the language.

~~~
gsnedders
Because, fundamentally, replacing any part of the web platform is _hard_. The
last big, breaking, change was GIF -> PNG. HTML -> XHTML might happen once IE
< 9 becomes irrelevant, but I doubt it.

But, in the case of JS, there's one major practical constraints: Introducing a
new language must not regress performance of JS. (Why? There's an absolute ton
of JS on the web. Getting 1% of the web using a new language able to be
quicker doesn't matter if you regress 99% of the web.)

You may think, "Sure, that's easy. You just add a second VM, entirely disjoint
from JS!". Unfortunately, it's not that easy: if you allow the languages to
coexist in the same page, you then need to GC across both languages (as some
objects are shared between the two runtimes, primarily those relating to the
DOM), and cross-VM GC is an active research area, where nothing has been shown
without at least a 10% performance hit to both GC impls.

Well, then, how about having a "generic" VM that runs JS within it? You're
going to have an uphill battle to get performance equal to current JS VMs,
because their bytecode (ignoring V8 for now!) encodes a lot of high-level
semantics of JS, which means any new language, to have good performance, would
have to share a lot of semantics with JS. This inevitably puts massive
limitations on what any new language can be like, and restricts it to being
"JS-esque".

So what can we do? There are two basic options: subset JS, though inevitably
this doesn't sort out things like `==` v. `===`, but you can get to something
where you can statically check you're using a sane subset (e.g., not using
`==`, not using any undefined variables, etc.); or, write some language not
overly dissimilar to JS and compile down to JS (the "not overly dissimilar"
restriction is a practical necessity as you can't really afford to send large
language runtimes and standard libraries over the wire). In both cases, JS is
ultimately the target thus it's important to keep on fixing what can be fixed
with JS (e.g., the lack of a module system, the lack of memory-efficient data
structures), but both can improve the situation over unrestricted JS as it is
today.

~~~
esrauch

      HTML -> XHTML might happen once IE < 9 becomes irrelevant, but I doubt it
    

I think XHTML is actually declining in popularity, offset by html5.

------
Tloewald
Replace article with link to Crockford and John Resig's advanced JavaScript
tutorial.

<http://ejohn.org/apps/learn/>

Any list of gotchas that omits discussion of falsiness, objects vs arrays,
array-like things that aren't arrays, the array sort function...

And the throwaway comment about JavaScript being poorly designed is facile and
annoying Every language anyone uses has warts.

~~~
PommeDeTerre
Nobody is suggesting that other programming languages don't have oddities or
problems. But very few, aside from perhaps PHP, are riddled with the huge
number of senseless, if not outright stupid, issues we see with JavaScript.

It's pretty telling that Crockford's "JavaScript: The Good Parts", which is
the most widely-recommended book by the JavaScript community, essentially says
to not use huge parts of the language. One doesn't have to intentionally avoid
so much core functionality when using most other programming languages.

~~~
jeswin
Have you actually used non-trivial Javascript in any project? You repeat the
exact same thing in _every_ JS thread here, and most of it seems to come not
from any real experience in JS.

It could be true writing good JS is a little harder than good Java, especially
on the server. This is a consequence of the callback oriented nature of JS
frameworks and APIs. Once you get used to it, it wouldn't really matter and
there are real performance benefits that come out of it.

As for the many warts people bring up, how hard is it to follow a few good
practices? If those trivial issues can't be overcome, that person will have
problems programming in any language.

~~~
PommeDeTerre
I must admit, I do have a great deal of experience with many programming
languages, many frameworks and libraries, many operating systems, and many
platforms. Some of this experience predates the web.

I have indeed worked on multiple large JavaScript code bases. Some of this
work was in the late 1990s (using Netscape Enterprise Server's support for
server-side JavaScript, unfortunately), and some of it within the past few
years.

Having worked on large JavaScript-based systems, in addition to ones written
in languages like C, C++, Java, C#, Fortran, COBOL, PHP, Erlang and several
proprietary languages/platforms, the problems with JavaScript become
excruciatingly clear. The wider your experience, the more obvious it becomes
how terrible JavaScript is.

The problems with JavaScript, especially for any sizable development projects,
run far deeper than merely needing to stick to some "good practices". It just
doesn't provide the infrastructure needed for anything but small-scale
development. Its many flaws render it further inadequate for any serious use.

Now, that won't stop some people from trying to push it far beyond what it's
capable of. The results are never good, however, and generally inferior to
what could be obtained when using other technologies.

~~~
stevekwan
I love JavaScript, but there's no denying that large aspects of the language
are somewhat ill-conceived. Crockford himself says this.

Once you know which pitfalls to avoid it's possible to write some really
elegant code, but the mere presence of those pitfalls causes a ton of problems
when you bring in engineers from other programming languages.

I find it kind of concerning that when someone criticizes JavaScript,
everyone's first response is, "he must not have any experience with the
language." That's an unfounded personal attack and ignores the crux of the
argument.

Look, we love JavaScript, but it doesn't do us any good to pretend it's
perfect. It'd be much easier to ramp up new engineers on the language if we
admitted its flaws and made efforts to educate "the right way."

~~~
Tloewald
"crockford himself" has done great things fo Javascript but he's also not the
last word on it. He himself admits that some of his ideas about JavaScript
were wrong and resulted from his pre Javacript baggage. E.g. The model he
suggests for conventional inheritance in "The Good Parts" does not, iirc,
actually work as advertised and in any event isn't needed.

The interesting thing to me about JavaScript is that insofar as it lacks
"crucial" language features it turns out to provide the necessary tools to
build them yourself. Exactly gow do you want inheritance or modules or
whatever to work? E.g. While JavaScript doesn't impose a module structure it's
very easy to come up with one, and because you build it yourself you can tweak
it to deal with your exact needs rather than adhering mindlessly to "patterns"
developed for working around the shortcomings of more tightly defined
languages (Java, cough)

Java programmers moving to JavaScript seem to write horrible code because the
freedom to actually just do stuff rather than build boxes with tiny weird-
shaped holes cut in them to package pieces of functionality is so alien.

I wish Python, with its (fewer) warts were as ubiquitous and useful as
JavaScript, but it's not, and Javascript is pretty darn good.

~~~
stevekwan
I'm not disagreeing with you in any way, shape or form. JavaScript is an
AWESOME language for both productivity and results. But I think we're doing
ourselves a disservice if we assume that anyone jumping right into the
language is going to immediately understand it.

Like you said, bad code is somewhat inevitable when you drop a classically-
trained OOP programming into JavaScript. And that specifically is not a fault
of the language. But I think we can all do a better job of pointing newbies in
the right direction.

------
babuskov
TL;DR: Poorly written shallow analysis.

Really, he should've used a different title, say "JavaScript Rant"

The author complains about the was language is designed, and says "might", "in
some cases", "this is wrong" etc. without showing real examples. And he's also
dead wrong on a few facts (like JS being a pure functional language).

Looks like "let's bake something in 5 minutes" and post it to HN to get 57
points for nothing.

~~~
yuchi
I'm ashamed that a lot of rants about languages get so many points here on HN.
This article, in particular, is written by a JavaScript ignorant, which for
the first time approaches the language. Even worse, "JavaScript the good
parts" is a good read, but it shouldn't be promoted as the _de facto_ bible of
JavaScript as it is: it's old, outdated, lacks a lot of the recent changes and
promotes a lot of patterns which became anti-patterns.

An example of my last sentence: have look at how Titanium SDK (v2.1.x) folks
designed their "parasitic inheritance" architecture following Crockford's
book. A terrible, unusable, instable, un-hackable (wrong) use of JavaScript.

EDIT: I don't know if Steve Kwan is actually a _noob_ or not, but it looks
like. Eg:

    
    
        identifier = function () {};
    

this is not one of the examples of "ways to create a function". This is
actually an assignement using a function expression. These are the 3 REAL
ways:

    
    
        // As expression, in an assignement or as argument.
        (function () { /*...*/ });
        // As expression, but with a name given to it.
        (function $identifier$ () { /*...*/ });
        // As a declaration, which gets HOISTED!!
        function $identifier$ () { /*...*/ }

~~~
yuchi
Addendum. Oh gosh:

    
    
        var someObject = new Object();
    

Is that real?

~~~
stevekwan
I did not put that there because it was the best syntax. :) I put it there
because I felt it was most likely to be understood by someone new to the
language. I assume you're implying I should have used {}?

~~~
yuchi
Yes, not for the syntax itself, but for a mere "smell" of code quality. The
use of "new Object" is found only in two kind of JS code incredibly old or
incredibly badly written.

~~~
stevekwan
I hear you completely. But understand that my intent here was not to write
idiomatic code, it was to write code that an outsider to JavaScript would
understand. I worry that the {} syntax, while simple/elegant/preferred, may be
somewhat less obvious to a new person who is unfamiliar with JavaScript's
object literals. In any event, I've updated the article to include both ways.

Regarding variable hoisting, I am trying to keep this article short, concise,
and focused on the big offenders when it comes to gotchas. The only reason I
didn't discuss hoisting is because I felt it would introduce too many concepts
at once. To me, hoisting is kind of "level 2," whereas understanding why var
is required is "level 1."

And on a side note, I appreciate all the feedback you're providing here - I
really do. That's why it's on GitHub and not some blog somewhere. But I would
suggest that we separate personal attacks from code criticisms. If you don't
like my approach with this article or you find something that's flat-out
incorrect, by all means tell me. As a human I am prone to make mistakes -
maybe moreso than others. :)

But please avoid making value judgments about a person you don't even know,
such as calling them an ignorant. It's bad enough when people behave this way
on the internet, but if that kind of mentality starts to seep into your "real
world" life too, it'll start having serious effects on team relations and
employability.

~~~
yuchi
I'm sorry for my personal stakes at you. And honestly I have to say I'm biased
against javascript articles, because I'm so used to find a strong lack of
experience and knowledge in them. I appreciate your answer, and please pardon
my rudeness.

At the same time you could make a "level 1" article a lot more adherent to
reality. For example, you could completely jump over that "function creation"
section entirely, and simply do a clear explanation of what an expression is
in JavaScript, and how to spot them.

Again, thank you for your personal advices, and thank you for your politeness
(as opposed to my manners).

------
Kiro
The answer to "Why are there so many different ways to declare a function?
What are the differences?" doesn't really answer the question.

No error:

    
    
      <script>
    
      myFunction();
    
      function myFunction() {};
    
      </script>
    

Error:

    
    
      <script>
    
      myFunction();
    
      var myFunction = function() {};
    
      </script>
    

A correct answer should explain why this happens in order to understand what
the difference really is about.

~~~
STRML
I can take a stab at it.

All variables are hoisted to the top of a function, where they are defined as
'undefined'. This is confusing, I know - there is actually a difference
between an undefined variable (accessing it will cause a ReferenceError) and a
variable defined as 'undefined', which is in many cases identical to null,
except in object syntax.

An example you can run in your inspector:

    
    
      function foo(){
        console.log(a);
        var a = "string";
      }
      function bar(){
        console.log(a);
      }
      foo(); // logs 'undefined'
      bar(); // throws ReferenceError
    

Why does this happen?

Well, this is because of the variable hoisting. Before running a function, the
interpreter scans for any var definitions and 'hoists' them to the top of the
function, where they are set to undefined. This leads to the strange situation
where defining a variable after it's been accessed (as in foo()) actually
prevents an exception.

The same is true of functions defined with the 'function name(){}' syntax. As
opposed to the 'var name = function(){}' syntax, the entire function
(including the definition of the function!) is hoisted to the top of the
containing function. So this will work:

    
    
      function foo(){
        bar();
        function bar(){
          console.log("works!");
        }
      }
      foo();
    

This can be confusing but if used properly can be very helpful in refactoring
your code. For instance, there are times when I've easily cleaned up code by
just putting them into separate function definitions within the parent
function:

    
    
      // old version
      function longFunction(){
        // 50 lines of code
        // awful, messy
      }
    
      function refactoredLongFunction(){
        doFirstThing();
        doSecondThing();
        doThirdThing();
    
        function doFirstThing(){
          // ...
        }
        // other function definitions
      }
    

This prevents a pattern I see in a lot of JS libraries that drives me _nuts_
\- defining functions at the top of a closure, then calling them at the
bottom. I very much dislike scrolling 100 lines to see the actual action
performed by a function. Using the above pattern leads to much more readable
code, IMO.

If you'd like to know more about function and variable hoisting, this is a
good read: [http://www.adequatelygood.com/2010/2/JavaScript-Scoping-
and-...](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting)

~~~
ajanuary
> Before running a function, the interpreter scans for any var definitions and
> 'hoists' them to the top of the function, where they are set to undefined.

A little off topic, and completely trivial and petty, but it kinda bugs me
when people talk about it as if the interpreter is moving variables around.

Moving variables around like that seems like a completely nutty thing to do,
because it is. You can't give someone an explanation of the trade-offs as to
why Javascript does it, because it doesn't. So hoisting is just presented as
another thing Javascript does that makes it weird.

Really it's not actually moving anything, it's just an artefact of the same
scoping rules used in lots of languages, compounded by allowing variables to
be referenced before they're assigned.

Variables aren't moved, they behave as if they were moved.

------
idbentley
The gotchas are fine, but the explanations are very poor. I'd like
justifications or references.

I would prefer Ben Alman, Douglas Crockford, John Resig, Paul Irish, or one of
the many talented people writing about javascript if you were actually
interested in understanding the gotcha's on this list.

Also, I wish authors would be careful to distinguish js from jQuery. Yes it's
standard now, but preferences change with time.

~~~
stevekwan
I tried not to get too deep into the explanations because I really, really
wanted to keep this to a short list that could be scanned and grokked.

Truth be told, if someone wants an explanation of some of JS's weirdness,
there are far better articles out there they can Google to meet that need. :)

------
killahpriest

        function myFunction(arg1, arg2) {};       // This is OK, but...
        var myFunction = function(arg1, arg2) {}; // This is best!
    

_The second option is better, and is properly scoped, but it leads to certain
syntax problems once you get into closures._

What problems? How does assigning the function to a variable help avoid
needing to make a closure for _this_?

~~~
jrajav
The first one will be hoisted to the top of the function (the whole
declaration), the second one won't (the variable will, but not the function
expression itself).

EDIT: To clarify:

All variable declarations in Javascript do indeed get hoisted to the top of
the scope, but with function declarations even the function value itself gets
hoisted. So for instance, this returns 'two':

    
    
      function foo() {
        function one() { return 'one'; }
        return one();
        function one() { return 'two'; }
      }
    
      foo();
    
    

But this returns 'one':

    
    
      function foo() {
        var one = function one() { return 'one'; }
        return one();
        var one = function one() { return 'two'; }
      }
    
      foo();

~~~
33a
What? I have no idea what you are talking about. Both get hoisted to the top
of closure scope...

~~~
jrajav
See my edit.

------
UnoriginalGuy
Cannot decide which is a worse language, Javascript or PHP.

It is quite amazing how much effort people putting in to designing the
"perfect" language, and yet we continue to see highly flawed languages get
popular.

I wonder if we'll ever see a replacement for JS in the browser? Maybe just a
JS-strict with all the gunk and strangeness removed (and maybe the libraries
cleaned up a LOT).

~~~
borplk
I hope to see the day where the web is language agnostic. Why the hell do we
have to be tied to one single language?

~~~
PasserBy2
The worst part is the hype. Pretending it's cool, like there is a choice.

------
factorialboy
>> "Closures are a concept that appear in pure functional languages like
JavaScript"

Err.. since when did JavaScript become pure functional?

~~~
bwilliams
I saw and asked the exact same thing.

~~~
stevekwan
Good catch. I accidentally JavaScript. It's been fixed. Thanks!

------
geuis
The tone of this article does absolutely nothing to help a new learner. While
mostly factually correct, constantly complaining, whining, and saying what a
stupid design decision this or that was helps in no way.

Every language has quirks. In the case if js, the things your complaining
about like var and function declaration are features of the language.

~~~
stevekwan
My apologies if I came across this way. The intent was not to whine about var
or function declaration, but rather to provide clear direction about a
standardized "okay" way of doing these things without causing yourself undue
headaches.

So please don't interpret my calling these issues out as whining. Just trying
to make new people aware that they are there. :)

If, on the other hand, I am legitimately WHINING and not realizing it, also
feel free to tell me where so I can fix it. Thanks!

~~~
geuis
Fair enough. Definitely not a personal attack or anything. I used to have the
very same thoughts until I really learned how powerful many of those confusing
things are.

~~~
stevekwan
I've gone through and removed some of the bristly "flavour" language. If you
want to scan through it again and look for more offenders I'd be greatly
appreciative.

------
lucian1900
JavaScript is most certainly _not_ a pure functional language.

------
EzGraphs
There have been a lot of articles re-hashing Crockford's analysis floating
around recently. These have been valuable, but they tend to focus on the same
topics in the core language (largely concerned with scope, use of closures,
behavior of basic data types, and functional programming). In web development,
the DOM and events end up being a more common area where I and other devs are
tripped up. A few things I wish I knew before a deep dive into an large scale
JavaScript project:

1) Newly added elements will not respond unless events are bound to them. One
solution (thinking in jQuery here) is to bind events higher up the DOM.

2) Each line in code may not simply execute in sequence. For example,
asynchronous ajax calls require subsequent calls to be nested in callbacks.

~~~
joshuacc
Regarding #2, I highly recommend reading Trevor Burnham's excellent book
_Async JavaScript_. It goes into a great deal of detail explaining how async
operations work, and ways of dealing with them.

------
stevekwan
Wow, glad to see this is stirring up a lot of discussion. Thanks for all your
contributions guys.

There are a ton of comments down below with a ton of criticisms and
suggestions. I will attempt to summarize and respond to the key ones here:

#1: The list is missing a lot of very well-known JavaScript gotchas.

That's intended. My goal here is not to provide a complete, comprehensive list
of all known quirks with the language - those exist in far better fashion on
the web already. Rather, my goal is to create a simple list of issues that I
KNOW will trip up newbies out of the gate.

Oddness with truthiness, undefined and arrays is definitely irksome, but from
my experience people tend not to run into those problems until they've already
written a good chunk of JS. On the other hand, issues like var, confusion over
closures, and the this keyword come up very quickly - almost immediately.

#2: The list seems very negative and biased against JavaScript.

My apologies, as that was not the intent at all. JS is great. But it is also
extremely flawed and there are some things flat-out wrong with the language.
I'm definitely not the only person who says this, either. :)

It's a great language to work in and you can do some wonderful things with it
once you grok it, but if we're going to be completely objective, we have to
admit that it has some definite problems that make it hard to learn.

#3: This seems full of preferences, not hard-and fast rules.

That's definitely by design as well. I circulate this list out to my team and
so it has my fingerprints all over it.

If this is a real sticking point with you guys and you feel it would be better
having that stuff removed, please send me some pull requests and I'll be happy
to review.

#4: The author comes across as snarky and unhelpful.

That's just a personality flaw and I apologize for it. :) I didn't want this
piece to be dry and I injected a bit of voice. If you feel it's actually
detracting from the article, please feel free to shoot me some examples and
I'll clean it up.

~~~
stevekwan
Oh, and one more thing. If you see anything in there that's flat-out WRONG -
not just a preference or stylistic choice, but actually WRONG - by all means,
shoot me a pull request! That's what it's there for.

I see a few of you already have, so thanks!

------
phaedryx
Because of semicolon insertion, Allman-style braces are frowned upon.
<https://www.google.com/search?q=javascript+brace+style>

~~~
ufo
I would just like to point out that people tend to blow the semicolon
insertion thing out of proportion. For braces it really only comes up when
returning object literals and for other things there are just a couple of
features that can bite you (starting lines with parenthesis or array literals
and so on)

<http://inimino.org/~inimino/blog/javascript_semicolons>

Sure, its best to always explicitly use semicolons but its not as dangerous to
forget them as most make it sound.

~~~
PommeDeTerre
While semicolon insertion itself does cause many problems, the mere fact that
it exists as a "feature" of the language is perhaps a bigger problem.

There's no justifiable reason for it to exist. The drawbacks should have been
clear from the moment the concept arose, and it should have been scrapped
before ever having been implemented. That's the only sensible response to it,
after even a minimal amount of analysis.

A missing semicolon should be treated as an error, causing the execution of
the script to be immediately halted, and the programmer notified of it. It is
as simple as that.

------
nicholasjarnold
Thanks for this, bookmarked.

I actually find little quick explanations like this extremely pragmatic and
useful. I don't do a whole lot of JS, but I certainly need to dive in
occasionally. Having quick references like this one readily available is
preferable to finding my Crockford book and flipping through the pages. If you
need to develop a client-side app or do heavy JS coding, maybe read the
Crockford book...but if all you need to do is get some shit working real quick
links like this one are invaluable.

------
cpleppert
This list isn't even well thought out at all and is more just a rant about
some random stuff. I'm not a big fan of the javascript type system in any case
but this isn't a real critique of it.

At some point just like Monads you just get the javascript type system and
don't worry about it anymore. It is what is. No amount of gotchas will get you
over the hump; you have to actually understand it. At least it isn't syntax
like C++ where you find out in a WTF moment that the parser is doing something
insane.

------
Eugen_RS
Some Gotchas should be cached by the ECMAScript 5's "strict mode", see
[https://developer.mozilla.org/en-
US/docs/JavaScript/Referenc...](https://developer.mozilla.org/en-
US/docs/JavaScript/Reference/Functions_and_function_scope/Strict_mode)

------
nkg
Very instructive. I stumbled upon some of these "gotchas" and had to find a
solution by myself then. I felt like I have a duty to share this with my
french fellas so I translated your article on my blog (with © and ®)
monlouis.tumblr.com

------
rartichoke
You should jsperf your function definition advice. The standard "function
foo() { ... }" way is over 10x faster than the "var foo = function foo() { ...
}" way or any other variant.

------
SonicSoul
gotta be honest.. not loving the tone of this post.

40% of it just keeps droning on about how noobs will fall for these traps, and
saying things like "If you are new to JavaScript, I suggest avoiding the this
keyword".. as if these concepts are so mind blowing noobs minds will melt.

it does bring up a few good points but it could have been a lot shorter.. and
how is closure a common js gotcha? the list includes 4 javascript constructs
veiled into a rant.

~~~
stevekwan
I really didn't want to write that. Ignorance is never really a good solution.
:)

But from my experience, someone who is coming into JS for the first time is
probably not setting up a complicated object hierarchy - they're probably just
trying to figure out how to bind some events to a DOM element and get some
basic UI functionality. And they probably don't need to use the this keyword
as much as they think they have to.

I completely agree that this could be a bad decision on my part, or at least a
very controversial one. But I'd rather have truly new JavaScript developers
focus on things like encapsulation and closures before they get too far into
the this keyword and constructor/prototype.

------
nej
Highly recommend reading "JavaScript: The Good Parts" by Douglas Crockford,
it's an excellent book.

------
PasserBy2
It would be much easier to list the parts of JS that work as a non-alien would
expect.

------
lttlrck
Yay another one. This is what SO community wikis are for.

