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.
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.
there is little effort into changing this
Yes, nothing at all. https://wiki.mozilla.org/ES6_plansand it worked really well! at no point did i hear anyone say "i wish javascript wasn't so limited". it's just a vary playable language that's easy to learn and quick to use to hack things (or create entire frameworks out of). it's no coincidence that it's still so popular.
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.
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.
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.
This was something I picked up pretty easily (blame perl, I guess? I blame perl for lots of things.) The weird way in which coersion would interplay with {truth,fals}iness, however, took much longer and involved much weeping and gnashing of teeth.
> And the throwaway comment about JavaScript being poorly designed is facile and annoying Every language anyone uses has warts.
Agreed. The post was helpful (and the link to Crockford's book is arguably the single most helpful thing in the list) but the off-hand comment about ES being poorly designed didn't add anything to the discussion.
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.
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$ () { /*...*/ }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.In the second, the var myFunction gets hoisted to the top but not the function definition, which is why calling it produces an error. In the first, the whole function gets hoisted to the top.
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-...
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.
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.
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. :)
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?
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();Some people think its better to ditch named functions completely rather than learn exactly when its problematic and when it's not... which I'm not sure I completely agree with, but its probably a good advice to give to a new JavaScript programmer, as it basically behaves the same minus those issues.
CoffeeScript ended up removing named functions [2] [3] (with the exception of being used for "class" declarations, where its known they're safe) for that reason.
[1] http://kangax.github.com/nfe/#jscript-memory-management
[2] https://github.com/jashkenas/coffee-script/issues/366#issuec...
[3] https://github.com/jashkenas/coffee-script/wiki/FAQ - "Q: Is there any way to name functions, for reflection and recursion?"
edit: formatting
So no, I disagree that that's good advice to give to a new programmer.
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).
http://bonsaiden.github.com/JavaScript-Garden/
It's long but not THAT long. There is a strict set of JS with some of the gunk removed. I don't think they went far enough but such is life. I'm not expecting a replacement for JS in the browser. AFAICT the browser vendors aren't interested in getting a replacement language standardized. I do expect compile-to-js options becoming more popular.
There are a couple other problems that make building web applications hard but are not the fault of the language:
What I generally find is that people who think JS sucks don't actually know JS. They know Java or C# or something and can, without learning anything, put together something that runs and generally does what they want. Their success (no obvious failures) and comfort with the syntax (except for those damn unexplainable JS bugs) causes an overestimation of their capability.
Overestimation is a problem because their experience in programing allows them to write a complex chunk of code that has the wrong abstractions/organization. It's absolutely awful. The worst 20-150k sloc codebases I've run across were ALL written by Java programmers who tell me JS sucks. The problem was that they're doing it wrong. Applying the right patterns has led to a 50%+ line count reduction in all cases. JS is its own language. The architectural patterns that work come from functional languages and not classy languages. Classy patterns can work but you need to go all-in and add type checking a la Google Closure oriented code and that's rare in the wild. Finally, small modules as in the node.js community generally seem to be working.
On the other end, JS suffers (along with PHP) the part timers. This would be fine except that easy but wrong patterns become standard practice. I fought against the jQuery spaghetti pattern for years only to find people migrating to Backbone, which is better but also flawed–events don't provide state isolation and the simple idempotent view.render() falls apart in larger apps and the workarounds are nuanced or complex. Use Ember or Angular. They are NOT more complex than you'll need unless you're only making brochureware sites.
The third problem is that the DOM sucks. The API is bad and has cross browser issues but jQuery basically won that battle. The remaining and more subtle problem is that it's a mutable global variable that you must interact with. There are a variety of mitigation strategies with the most accessible being two way bindings.
If you discovered that the answer was one or the other, would it make you a better developer in any way? Would it help solve any problems the world has?
Perhaps you should look more into why the "Gresham's Law of Programming Languages" exists. Maybe the have better documentation, a more friendly user community. Maybe they fix more real-world problems and spend less time mentally masturbating over programmer porn.
Someone bringing up PHP when it's fairly unrelated? Check
Maybe focusing on the issue at hand would be something to keep in mind?
Err.. since when did JavaScript become pure functional?
Every language has quirks. In the case if js, the things your complaining about like var and function declaration are features of the language.
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!
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.
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.
I see a few of you already have, so thanks!
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.
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.
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.
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.
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.
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.