ponyfoo.com

JavaScript Is Awesome

Fix
A relevant ad will be displayed here soon. These ads help pay for my hosting.
Please consider disabling your ad blocker on Pony Foo. These ads help pay for my hosting.
You can support Pony Foo directly through Patreon or via PayPal.

JavaScript is one of the most loved and hated languages out there. Some, can’t stand the stench of how obtuse it appears to be. Some appreciate the “anything goes” virtues of an interpreted language, and would marry JavaScript given the chance.

Behold: the “hate speech”.

  • Interpreted languages are too bug-prone
  • Callback hell, or how easily you can lose track of what’s going on
  • Awkward equality comparers, ==, === are infuriating
  • this is a mess
  • Anything goes. Loose typing, how pretty much everything can mutate into anything without notice
  • Nonsensical behavior like parseInt('08') === 0 (this one changed recently for V8)
  • Poor support for (classical) debugging, such as reasonable stack traces
  • Prototypal vs Classical inheritance
  • All things JavaScript suck

I disagree with most of the above, and I want to spend a few words addressing these concerns.

First of all, the vast majority of these concerns arise from the paradigm shift people experience when developing in JavaScript. Most people are accustomed to a compiler telling them when something is amiss. In JavaScript, however, there is no compiler, JavaScript is interpreted as it is executed. There are a few ways to work around (or mitigate) this concern.

One way to mitigate the impact of not being able to compile your code, is use strict. By the way, MDN is an extensive resource library on JavaScript you are not using enough.

use strict in JavaScript is reminiscent of Option Explicit, back in the Visual Basic 6 days. It’s merely a safeguard against silly mistakes, but it comes in handy.

A more definitive approach to solve the issue is to resort to a JavaScript compiler, such as CoffeeScript, or TypeScript.

I discourage taking this approach. Not only because languages like CoffeeScript tend to be very opinionated about how your code should look like, but most importantly, it isn’t JavaScript, it’s an entirely different language; even though it incidentally compiles to JavaScript.

The notion of using TypeScript is slightly less infuriating, since it’s a superset of JavaScript, rather than a different language.

Having said that, the fact that both compilers output pure JavaScript remains, which is reason enough to learn how to code in JavaScript properly by yourself, rather than have a layer of abstraction making coding style choices for you. It’s not like JavaScript is MSIL. MSIL is really hard to read, maintain, write, and everything in between, and generally not worthwhile to code in, unless you need to fine-tune performance, dynamically generate classes, or the like.

A “simple” program in MSIL might be:

.method private hidebysig static void Main() cil managed
{
	.entrypoint
	.maxstack 2
	.locals init (
	[0] int32 num)
	L_0000: ldc.i4.0
	L_0001: stloc.0
	L_0002: br.s L_000e
	L_0004: ldloc.0
	L_0005: call void [mscorlib]System.Console::WriteLine(int32)
	L_000a: ldloc.0
	L_000b: ldc.i4.1
	L_000c: add
	L_000d: stloc.0
	L_000e: ldloc.0
	L_000f: ldc.i4.s 10
	L_0011: blt.s L_0004
	L_0013: ret
}

JavaScript is not that obscure. JavaScript can be learnt. Compilers hinder your ability to do that. You should learn what a closure is. How to extend a prototype. How to use callbacks sensibly. There lies the real beauty of JavaScript code.

Demystifying JavaScript

  • Interpreted languages are too bug-prone

While it might be true that JavaScript code is harder to debug, and can definitely be harder to maintain when improperly structured. There are several tools at our disposal to prevent chaos.

You should treat JavaScript as you would any other language, and as such, you should Unit Test your code. There are several frameworks to pick from.

Client-side JavaScript might prove harder to structure than JavaScript in Node.JS. Frameworks like Backbone.js and Knockout.js can help you structure your code cleanly and without making an unmaintainable mess out of it.

  • Awkward equality comparers, == is infuriating

This one I’ll concede. The equality operators, == and != are a mess… They try too hard. If the values being compared are of different types, these operators will attempt to coerce these values using complicated rules that are not even transitive. Avoid them entirely. Use, as Crockford puts it, the “good operators”: === and !==. These return false in case of type mismatch, as would be expected.

  • this is a mess

We know how this story goes. I’ll illustrate with a bad example:

function Car(opts){
	this.wheels = opts.axles * 2;
	return this;
}

var compact = new Car({axles: 2});
var truck = Car({axles: 5 });

Now compact is a four-wheel car, while our Window became a truck, and suddenly has 10 wheels. Furthermore, this can be chosen through Function.prototype.apply, and otherwise changes depending on the context it’s being evaluated in.

Well, you have two options. One option is to ignore the damn thing, and don’t use this or new, after all, ignorance is a bliss. The other option is, you guessed it, learning how it works.

  • Anything goes. Loose typing, how pretty much everything can mutate into anything without notice

This one is, in my opinion, one of the biggest selling points in favor of JavaScript, which is more often confused with a drawback against the language. I’d rephrase this as JavaScript just works, in that whatever change you want to introduce to your code, JavaScript can accomodate. And as long as you are conscious about maintainability, such flexibility shouldn’t become a problem.

There are many oddities like this in JavaScript, more than in some other languages such as C#, fewer than in others. Most of these oddities are easily avoided, and their persistance stems from poor implementations in some web browsers. Others (such as for..in problems), simply come from the nature of a prototypal inheritance model.

  • Poor support for (classical) debugging, such as reasonable stack traces

Often overlooked is the ability to execute code on demand in a browser console, or writing debug messages which you can see in real time with no extra frameworks, and without altering the user experience. These are things you often can’t do in other languages either, once you get accustomed to these, you’ll find it way more productive to debug with a console and hacking away at the DOM, than to step through your code, and recompiling every time you add a comma.

  • Prototypal vs Classical inheritance

In JavaScript, things inherit from other things, and not from abstract concepts (or classes). This might be hard to wrap your head around if you are experienced in class-based languages such as Java or C#, but you’ll soon get over it, and begin reaping the benefits.

Conclusion

JavaScript is awesome, and you should love it more!

Liked the article? Subscribe below to get an email when new articles come out! Also, follow @ponyfoo on Twitter and @ponyfoo on Facebook.
One-click unsubscribe, anytime. Learn more.

Comments (4)

hopkinsth wrote

I saw this post on EchoJS tonight and felt compelled to comment because I’m not sure I’ve ever seen hiragana used as bullets before. I’d like to expand on your “anything goes” point a bit. For me, the power of JavaScript comes from its lack of much structure. “Classical” inheritance systems often rely on maintaining a rigid, formal structure between classes in an inheritance hierarchy, where classes can most often only be functionally modified at compile-time, discounting things like lambdas and so on. There’s some benefit to that, for sure. Sometimes it’s advantageous. But JavaScript is so interesting to me precisely because, although it it eschews that formality, it is not any less brittle for it. And, beside that, it’s easy to augment the built-in inheritance system with your own conventions, a-la Crockford’s “parasitic inheritance” or whatever he calls it.

I’m not a huge fan of any of the compile-to-JavaScript languages, but I’m glad they exist. I’d rather just write JavaScript. It’s not a perfect language, though there’s really no such thing. I write a good amount of PHP code at my day job—for me, writing JavaScript is just more pleasant.

Nicolas Bevacqua wrote

Not a huge fun of doing classical inheritance in JavaScript, but it’s possible, and not as awful as doing dynamic programming in a language such as C#.

CoffeeScript definitely helps some people, I can’t argue with that. It’s just I don’t think I could bring myself to write it, or recommend anyone to do so without good reason.

Glad you liked the hiragana! :)

David Hanson wrote

Ok I’ll address some of the points you have made.

JavaScript is not that obscure. JavaScript can be learnt. Compilers hinder your ability to do that.

This IMHO this is just wrong, compilers are your friend, on a code base of 100k+ lines of code the compiler can verify the integrity of your application without having to discover it at runtime. Further the compiler can perform optimization which you don’t need to be aware of.

The notion of using TypeScript is slightly less infuriating, since it’s a superset of JavaScript, rather than a different language.

Important to note here that TS is just JavaScript and one its major selling points is that its trying to give you the JS of the future now. Language features such as classes & modules in ES6 are a way for developers to avoid writing the verbose javascript they normally would.

You should treat JavaScript as you would any other language, and as such, you should Unit Test your code.

I agree with this but 100% coverage is unrealistic for most teams and I would argue a waste of effort.

Awkward equality comparers, == is infuriating

“this” is a mess

You seem to agree they are broken, so not going to argue that. The point is they are probably the most important features of a language. If you can’t get that right then the whole language is in trouble.

Anything goes. Loose typing, how pretty much everything can mutate into anything without notice

This is not good at all on large pieces of software. Mutability has been proven to introduce bugs, especially as we move to a world with more concurrency. JavaScript is not going to scale well in this aspect AFAIC.

Nonsensical behavior like parseInt(‘08’) === 0

Agree just avoid.

Often overlooked is the ability to execute code on demand in a browser console, or writing debug messages which you can see in real time with no extra frameworks, and without altering the user experience. These are things you often can’t do in other languages either, once you get accustomed to these, you’ll find it way more productive to debug with a console and hacking away at the DOM, than to step through your code, and recompiling every time you add a comma.

This is so far what is expected of moderm debuggers its laughable, what about when you work with webworkers, what about drill down into debug values? Also many static languages support console.log in some format. c# has debug.WriteLine() which you can view using a tool like DebugView. On “Recompiling” well yes with C# or Java you do, but with TypeScript for example you can just save the file and continue. The compiler does not have to be in your way.

Prototypal vs Classical inheritance

Yeah agree with you on this, two different approaches and they differ slightly. However in classical inheritance you can use polymorphic behavior on base types. In JavaScript its structural and this leads to nasty little hacks. Classical inheritance for the win! :-)

Nicolas Bevacqua wrote

Strictly in the case of JavaScript, I disagree that compilers provide you any integrity value. You should be using JSHint or some other lint tool, rather than a full-fledged compiler.

I definitely didn’t mean 100% coverage, but definitely some coverage.

Loose typing can be an issue from time to time, but I believe it’s power far outweighs the problems it might bring, if used sensibly.

Appreciate your input!