> JavaScript is actually an incredibly flexible and effective language.
== vs ===
No integers.
Assignment is declaration.
Prototypes.
Curly brackets & semicolons.
Semicolon insertion.
It may be flexible (in the sense that an Alfa Romeo driven into a telephone pole at 120 mph is flexible), but it sure as heck ain't effective. JavaScript is the great shame of the computing industry: that it exists, and that it is used, and that it is used in more than just the browser, is an indictment of our entire profession.
JavaScript: take off and nuke it from orbit. It's the only way to be sure.
JavaScript: you'll envy the dead.
JavaScript: a mistake, carried out past the point of absurdity.
No amount of cute phrases will change the fact that it is being spread by people who actually understand its flexibility instead of focusing on something that rubs them the wrong way (which, most of the time is the result of working with other, often shiver enterprisey language(s) and thinking that that's how it's done) quite effectively and there's no sign of stopping for its growth.
And that is good.
With things like rust and go backing us up in places where more verbose and static code is beneficial (for performance?) we are finally entering new age which leaves closed corp-controlled "enterprise" things (java, net - looking at you) behind.
My litmus test for whether an argument for JS is valid is replacing "JS" with "PHP" in my head and seeing if it reads the same. PHP did all the same things, but that doesn't make it a good language, it just makes it a language that's easy enough to learn for it to get popular.
I think the main reason for the popularity of object-oriented languages is that the design corresponds more closely to the physical world, which makes it easier to reason about the architecture of the software.
Not exactly. You can declare variables separately, if you want. In fact, a "var x = 42" statement will actually be split into "var x;" at the top of the scope and "x = 42" wherever you actually wrote it by the interpreter. The specified behaviour is a little weird and non-obvious, but once you know it, you know it.
> Prototypes.
That's a matter of taste (plus the problem of optimisation at the VM level, admittedly). Besides which, you can basically use prototypes to do classes, if that's your bag, and of course we have class syntax now anyway.
> Curly brackets & semicolons.
Semicolons are optional, which however you complain about below. So are some curly braces. The only alternative to having some kind of block delimiter would be significant whitespace, which is a perfectly legitimate preference but has its own warts.
> Semicolon insertion.
Around which the rules are fairly simple to understand. It's possible there's just a better way to do it (I know Go has ASI, for instance, but have never heard anyone complain).
---
I find this a most peculiar list of JS warts (what, not even a shout out for ==, bizarre implicit type coercions, etc?) There's no doubt it is a deeply flawed language, a big part of learning it is learning about the various spike-pits lying in wait for you, and the extra tooling required to mitigate its flaws comes with its own set of costs.
At the end of the day, though, you can write pleasant, readable and - yes - effective code in JS. There are worse languages to be stuck with, as long as you watch out for the spike-pits.
> You can declare variables separately, if you want.
The issue is that 'fop = 1' is not an error (outside of strict mode), even when I mean 'foo = 1.' Automatically creating variables makes what could be compile-time errors run-time instead.
> Besides which, you can basically use prototypes to do classes, if that's your bag, and of course we have class syntax now anyway.
Which I also find to be a mistake. Generic functions are the right way to do OO.
> The only alternative to having some kind of block delimiter would be significant whitespace
The block delimiter I prefer is () grin
> It's possible there's just a better way to do it (I know Go has ASI, for instance, but have never heard anyone complain).
Yes, whereas good practice on JavaScript is to always use semicolons (because its semicolon insertion is wrong), good practice in Go is to never use them (because its semicolon insertion is correct).
Bizarrely, I misread it as an overcomplicated ASCII art divider. Looks like I've got a JS VM in my head...
The fop typo - while I acknowledge that there are plenty of gotchas of this kind in javascript, a gotcha that will be caught by strict mode barely even counts in the grand scheme of things. Strict mode then gives you slightly better protection than in many otherwise more robust languages (Python and Ruby, for example).
On the ASI side, I don't see how it can be 'incorrect' - it's a well specified behaviour obeyed consistently, so far as I can tell, across the vast bulk of implementations. It may be a bad design, but that's a different thing. Go's version is certainly easier to explain in a paragraph or less.
I'm assuming by generic functions you're talking about eg. Clojure protocols or Haskell typeclass functions or stuff like that, which I also prefer (I also like round parens). But at this point, you're just criticising JS for not being $LANGUAGE_I_LIKE, which it isn't, obviously, but does not count as a terrible sin in and of itself.
I return to my main point - no, JS is not a great piece of language design, but it's hardly 'nuke from orbit' bad. There are certainly things I'd rather be working with, but equally there are worse fates that we could have been stuck with after the browser wars. "Life — the way it really is — is a battle not between good and bad, but between bad and worse".
> Bizarrely, I misread it as an overcomplicated ASCII art divider.
No worries!
> Strict mode then gives you slightly better protection than in many otherwise more robust languages (Python and Ruby, for example).
I really dislike that aspect of Python; IMHO it's a pretty bad flaw.
> On the ASI side, I don't see how it can be 'incorrect'
I think it's incorrect in the sense that it's such a bad design that the Right Thing to do is to always use semicolons manually (with the corollary that if the design is such that one never uses them — as with Go — then it must be correct).
> I'm assuming by generic functions you're talking about eg. Clojure protocols or Haskell typeclass functions or stuff like that
I'm thinking Lisp's multimethods. Behaviour doesn't really belong to one object or another, an uniquely privileging the first argument is just weird.
> I return to my main point - no, JS is not a great piece of language design, but it's hardly 'nuke from orbit' bad.
If it weren't for the installed base, I think JavaScript would be only two steps ahead of INTERCAL …
I think with the "No integers" part that isn't entirely true JavaScript has typed arrays now. So you could get an array of ints that way. I'm not familiar with them and whether they behave in a similar way as an int in a typed language like Java or C++, but from my reading it seems the integer view behaves (output wise) in much the same way as other typed languages integers.
Even using Class syntax you're still locked into prototypical inheritance model. There is no classical inheritance in JS. (Probably a backward step in UX to call it "Class")
Yes, but you're locked into the subset of prototypal inheritance that basically is class inheritance. A class is, fundamentally, just a prototype of a particular kind.
The flexibility of JS is not how the language is designed, it is the hole that the language is filling.
The fact that using JS you can write a browser based app, a mobile app, backend software, configuration files and flat data files (JSON) without switching gears is the flexibility.
I would also argue that if you really don't like JS, you are using the wrong tool for whatever job you are trying to do.
That'd be fine, if there was any other tool that worked in a browser. Sure, you can transpile from some other real language, but it's still javascript when you finish up, with all the foibles and warts that haven't been fixed in twenty years.
Unfortunately, instead of going back and fixing core deficiencies in the language standard, it looks like ES6 & 7 are thick cakings of lipstick on the pig.
> "Unfortunately, instead of going back and fixing core deficiencies in the language standard, it looks like ES6 & 7 are thick cakings of lipstick on the pig."
The only truly terrible part of JavaScript is all the implicit coercions around equality checking. It would actually be a decent language if it reported type errors instead.
There are a few other smaller issues that are nuisances, like not being able to actually check if a value is a number, but I think coercions cause the most headaches for discoverability and debugging.
It would stop working if you did it NOW. That's irrelevant to the point that that's how JS should have worked from the beginning. Also, they can add these semantics to JS now too with a new type of strict mode without breaking anything.
As for how painful it would be, your claim is a total fabrication. Other dynamically typed languages are a pleasure to program in without implicit coercions everywhere. JS is widely considered a pain. Coincidence it is not.
I find that is widely enjoyed by the "silent majority" and decried as a pain by a very vocal subset of developers. It's a little surprising that 1 + '1' is '11', until you spend a little time and learn the rules instead of fighting them - then you start doing your work in a way that uses that to save time. It's not great for everyone, but I like it - and I know a lot of other good devs who prefer the answer '11' (when you understand the fairly simple rules) to 'OMFGNOIQUIT'. I find "Number beats bool, string beats number" for implicit coercions covers 95% of cases where it would actually matter. For the other 5%, just type it in the console.
Because I like it that way, doesn't mean you have to as well - but it also doesn't mean that because you don't like (or even most of the commenters on HN) it it is "widely considered a pain".
> It's a little surprising that 1 + '1' is '11', until you spend a little time and learn the rules instead of fighting them - then you start doing your work in a way that uses that to save time.
You are omcpletely underestimating the complexity of JS's implicit coercions. If you haven't already seen it, watch the Wat talk [1].
Finally, the fact that you need the console to even understand the meaning of a code fragment is a perfect example of language failure.
> Finally, the fact that you need the console to even understand the meaning of a code fragment is a perfect example of language failure.
Isn't that the case for every language with polymorphism? Even C, once you add function pointers to the mix.
I've certainly heard polymorphism and OOP criticized on these grounds, but unless you're a hardcore kernel or embedded developer, that ship sailed about 25 years ago. Everybody uses debuggers and log statements these days. Expecting to be able to look at a code sample in isolation and know what it does is unrealistic for any large-scale system.
> Expecting to be able to look at a code sample in isolation and know what it does is unrealistic for any large-scale system.
My number one favorite thing about Go: you can look at a code sample in isolation in a large-scale system and know what it does.
Why? Every identifier is either lexically scoped or lives in a module. There are about 6 control structures and they all do what they look like they do. Operators are all defined over a small set of well-defined primitives, they can't be overridden. Closures, callbacks, and non-linear control flow are rare and obvious. There is no way for code to be skipped by exceptional control flow apart from the single escape hatch called panic().
It's really like no other language I've ever coded in. You can work in large codebases that are as clear as your average Go code, if you have strong guidance about what kinds of code complexity are acceptable and you are ever-vigilant about avoiding language pitfalls, but nothing is quite as freeing as knowing for a fact you will be able to parse someone else's code because there wasn't any way for them to write something you can't understand.
You still have interfaces. When you invoke a method on an interface, you don't know exactly which code will be called. It could do anything from crash to format your hard drive. In theory, the semantics of the interface should be well-specified and any implementation that doesn't conform to them is a bug, and Go culture holds pretty strictly to this, but there's nothing in the compiler that imposes solid restrictions on what the implementation of an interface can do.
If you're disciplined, you can write solid, easy-to-understand code in any language, Javascript included. I've worked on million+ line Javascript codebases and been productive (as a developer new to the codebase) within 3 days. But this imposes trade-offs in verbosity and flexibility that are often not worth it for most (non-Google-scale) JS codebases.
> Expecting to be able to look at a code sample in isolation and know what it does is unrealistic for any large-scale system.
I don't know why you'd think that. In a typed language, you simply look at the types and you know exactly the intended meaning of a code fragment ie. what inputs are needed, what outputs are produced, etc. That's not remotely the case for JavaScript due to its implicit conversions.
I'm with you except for wanting type errors. I like ducktyping and in coffeescript -- I know, I'm not cool -- you get the existential operator `?` which makes ducktyping really nice.
I really think the problem with javascript really boils down to the fact that it's still in beta and will never have the breaking changes necessary to move it to a 1.0 language (i.e . the ECMA committees commitment to not breaking the web). But, it's easy enough to get around that in new projects by using linters that get rid of the bad parts.
Duck typing for methods and such is fine if that's what you're into, but if you're checking for equality, you want type errors, period. Only like equals like. Doesn't matter if your language is statically typed or dynamically typed, equality means something very specific and it's very surprising when those expectations are violated.
Thank you for this post. We have a really bad habit of chasing "cutting edge" fads as an industry. It must come from the tendency of programmers to burn out and bow out, which exacerbates the tendency of young bucks to lack any respect for their elders. Software dev is still a very immature industry.
I respect Brendan Eich a great deal and I truly appreciate what he did for NetScape in 1995 by introducing JavaScript. What I don't appreciate is that we decided to extrapolate that madly-rushed, designed-and-implemented-in-less-than-a-week-of-all-nighters language not only into the default client side language for the web for the last 2 decades, but we have also allowed very badly informed people to start using it for server-side applications.
There has to be a way to bring order to this chaos. Any ideas?
I can't say that Javascript is the most fun language to use, but I think that's because given the way it's positioned, it has a bit of a hoarding problem. It's picked up the millenial issue that the stupid things you said in your teens are never ever going away, because they are permanently spread through the internet. Fun.
The amount of "Bad Things" does make stumbling hazards, which is why I'm completely convinced that if you can, you should use a saner language, but there's no <script type="python"> (yet?). In those cases, we need to fence off the trash, put up warning signs on the exposed wiring, tape a post it note to "v instanceof Array" and try to write the sanest javascript we can.
PHP7 is ok. They rewrote the parser to use a real AST which fixed a lot of the weirdness and inconsistency, threw out a ton of deprecated stuff, and made error situations saner by replacing errors by throwables. I like also that php is gradually getting strict typing as an option. Function signatures are strictly typed now, with class properties getting it soon. Plus, PSR guidelines have made the popular libraries object-oriented, namespaced and consistent. My main complaint with php these days is that it's starting to look too much like java with dollar signs.
Back in the day when I was just learning to program, I wrote a BBcode library in JavaScript. Not knowing any better, I made very liberal use of globals throughout my code.
I later went to go port my code to PHP 4 (that was current at the time). To my surprise I was getting all these errors about how crappy of a programmer I was (both from globals and from misspellings and related problems).
I'm honestly not sure how people hate PHP so hard and yet don't mind JavaScript.
For me it was things like "function_returning_array()[0]" working in JS but not PHP and other unexpected parsing weirdness like that. (Though I don't really mind PHP, just much of the code written in it :-) )
Single inheritance is awfully limiting which is what Javascript's prototypes provide. And structurally copying multiple prototypes into a single object to achieve multiple inheritance is an awful hack.
== vs ===
No integers.
Assignment is declaration.
Prototypes.
Curly brackets & semicolons.
Semicolon insertion.
It may be flexible (in the sense that an Alfa Romeo driven into a telephone pole at 120 mph is flexible), but it sure as heck ain't effective. JavaScript is the great shame of the computing industry: that it exists, and that it is used, and that it is used in more than just the browser, is an indictment of our entire profession.
JavaScript: take off and nuke it from orbit. It's the only way to be sure.
JavaScript: you'll envy the dead.
JavaScript: a mistake, carried out past the point of absurdity.