Javascript, the bad parts, and how to avoid them

I’ve started getting real with Javascript by October 2016. I started by reading some great books :

  • JS : The Good Parts
  • Eloquent Javascript
  • Building Javascript Applications
  • Javascript Design Patterns

And really, I loved it. I understand why Javascript gained so much in popularity :

  • It’s the de-facto programming language for client-code running in the browser
  • Since around 2009, it can be used as a server programming language, so using one language through the whole codebase is a huge plus
  • It’s dynamic, event-driven, uses an event-loop in a single-thread, which reduces concurrent programming complexity a lot
  • It has an elegant syntax, mostly because it provides functions as first-class citizens (read : your functions can be arguments and returned values as much as any variable, or any literal) and closures (a way to point to variables, even through they are out of the function itself), which enables a lot of great way to build composable code
  • It’s prototype-oriented (rather than class-oriented like Java or C++)

The biggest thing to me about Javascript is how light it is to write code. Remember how hard it was to declare and manipulate an array in C ? Remember how rigid are C structures ? In Javascript, you have literals, and much of the complexity is managed by the engine, so you’ll never have to deal with it.

This is great, because you can really focus on your product. You can declare an Array on the spot using literals and fill it with anything. You don’t care whether it’s a List, a Vector, or even a HashTable indexed by numbers (why not ? since Arrays are just objects with numerical indexes, erm, string numbers actually, this might actually make sense). Hopefully you’ll never have to know, and people seems happy with it.

Sadly, this design is what gives Javascript a lot of bad parts. Let’s cover them.

Types

Sadly, and probably the worst choice ever made about JS, is that it’s weakly typed. Variables are untyped, only values are, and what types are they ? It’s either Object, Symbol, String, Number, Boolean, Null (yeah), and Undefined (yeah, undefined is a type of his own). What’s even kind of ridiculous is that when you test that your variable is an object, you have to do this :

if (typeof myObject === "object" && myObject !== null)

Because your object can be of type Object, and still be null you know. 
And this weakly thing really is a pain because without types, the code is damn obscure.

How to fix : That’s where people started using TypeScript and FlowType. Adding type to Javascript is like adding chantilly on top of your chocolat ice-cream. It makes it so good you wont ever eat chocolat ice-cream alone, EVER.

Numbers

It’s terrible that numbers in javascript are double-precision floating points (i’ll talk about it in an article dedicated to representations). Which means you have no integer type. What’s the problem with it ? Just watch.

For god sake

Yeah, 0.1 + 0.2 is equal to 0.300…4. And well, this is terrible when you want to check 0.1 + 0.2 === 0.3 because, in JS, it turns out it isn’t.

Once again, to explain this, i’ll have to talk a lot about how floating numbers are represented in a computer, so for now just know this is barely the type of the icerberg.

How to fix : well this isn’t a bug per se, it’s just by design. You can work it out by using an other library, such as decimal.js

Coercion

The most painful topic about JS is coercion.

What is coercion ? Recall that JS has native types (Number, String…) and that variables are not typed, values are. When you do typeof myVar === "number" you are actually looking to know if the type of the value myVar is pointing to is a number. It’s important to understand that.

let myVar = 10; // typeof myVar === "number"
myVar = "Hello World!"; // typeof myVar === "string

Now, what happens when you want to do an operation with two variables, whose values are different types ?

let a = 10;
let b = "10";
let c = a + b; // ???

A decimal 10 is represented differently than a string 10. For example, the number 10 could be represented in 8 bits as 00001010. The string 10, is encoded using two ASCII characters* : 00110000 (48) and 00110001 (49).

In order to do proper calculation, the Javascript Engine must ensure both operands are of the same type. And JS tries to do the best for you, so in this case it will assume you just want to concatenate a decimal 10 to a string 10, and returns a string value of “1010”.

Why, thanks you JS

As I said before, because most of the implementation choices are done for you in the JS world, you have to be very careful. And you know where this might hurt you the most ?

User Inputs.

Imagine an user enters an amount he wants to invest for, let’s say, roulette. Because you are rude, you want to take a 1€ fee, so you naively do the following :

let totalCost = 1 + moneyInvested

The afternoon, you receive a message call about how a bastard you are that he wanted to invest 100€ but you actually took 1100€. Good luck with that.

How to fix : in order to avoid letting JS do the coercion job for you, you have to convert types yourself.

  • To convert a String to a number, go with parseInt
  • To convert a String to a float, go with parseFloat
  • To convert a Number to a string, use the .toString() method like (54).toString() (yeah that’s funny how native types all are Objects)
  • To convert a String to a Boolean, there’s no magic, you do var myBoolean = myString === "true";

Be mostly careful about coercion when it comes to condition and loops. It will bite you. Read this article for more in-depths about it.

Callback hell

To know this has been a thing…

I think this image says it all about what is callback hell, and why it’s named so.

How to fix : fortunately there’s been tons of solutions against this :

  • Promises : it’s a real game changer because you can easily see the flow of your app. You just chain “then”, passing the value from one callback to another, in a linear way. And you add a single .catch to handle whatever bad things could happen in the whole process
  • Async / Await : I said Promises were a game changer ? oh whoops. This one is the real deal. Now you don’t have any more then/catch, your code is just plain old imperative like it has always been, except you add async and await keywords here and there.
  • Generators : this is still an other way, kind of esoteric some would say, to handle side effects (because yeah, callbacks/promises/async await are really about handling concurrent operations, which are side effects). You might want to check out.

Global Variables

Yes, indeed, variables in Javascript are global whenever they can. And you know, Javascript is so cool, it doesn’t like to scream on you, so it let’s you do your mistakes and clean behind you. So, you can naively use a variable you didn’t ever declare, and it’s gonna be a global.

function foo() {
x = 10; // Whoops
}
foo();
console.log(x); // 10

If you are on the browser, it’s so well registered you can call it from the window object, like window.x .

Why global variables are wrong ?

  • That’s some space allocated you’ll never get back until you nullify them explicitly by calling window.x = null
  • It induces sides effects in your functions that are going to use that, which makes the code way more complex to understand
  • Other people could as well have used this variable for a library or something (which isn’t rare for browser UI libs). Worst than that, one could inject malicious code in that global that would make your code crash or worst, leak informations.
  • It’s hard to test global variables, because they are global, and their usage is hard to determine.

How to fix it : well, just never ever use them. There’s tons of way to get away without using global variables (such as closures and IIFE, i’ll talk about it in an other course). Always use let and const when you declare a variable, and if you’re not confident, use strict.

Wrapping Up

I think I didn’t even closely cover every bad things in JS and how to avoid them, but I want this list to be updated as much as possible, so please don’t hesitate to give some feedback, and subjects that I should cover. Thanks you !

Through there’s a lot of bad things in JS, recall it has been made in, like, 2 weeks, in a hard and competitive climax. Hopefully we somehow managed to take something out of it, like a huge ecosystem, some interesting programming schemes, and we made a lot of great apps.


*Actually, string encoding in JS is a bit more complicated than that, but that’s an other subject.