JavaScript Is Weird. And That’s Why We Love It.

According to the 2021 Stack Overflow Developer Survey, JavaScript is the most widely used technology among professionals and amateurs alike.

Some 61.51% of developers love the coding language. But that still leaves some 40% of programmers who prefer to stay away. So why is that? Well, there’s a fair degree of weirdness about JS, which could be one explanation.

Just check the example below:

 

JavaScript

 

In this article, we’ll run through why some JavaScript actions work the way they do (as opposed to how you might expect).

No hanging around, let’s get stuck in!

The oddities of Numbers vs Not a Number

Let’s start by looking at typeof NaN.

Many people ask why the entry to this operation is number. You can read a lot about this topic in the specifications, which state what numbers mean in JS:

‘Number type set of all possible Number values including the special “Not-a-Number” (NaN) value, positive infinity, and negative infinity’

But what exactly is “Not-a-Number”? In simple terms, NaN is something that tries to be a number — but fails.

An example could be something that:

    • Goes beyond the range of numbers supported by JavaScript
    • Tries to convert a string to a number, e.g., parseInt ('meow')
  • Divides zero by zero
  • Multiplies zero times infinity

And there are several more cases where the result cannot be determined by the actual numbers in the range supported by JS.

 

9999999999999999 === 10000000000000000

 

Once again, the result seems odd — so where does this bizarreness come from? The answer is similar to the previous case.

JavaScript uses floating-point numbers written using the IEEE 754 standard, which (like every number standard) has its limitations. In essence, when you pass a certain limit, natural numbers (integers) are no longer exact. You may now be asking, “So, is there a way to check this border?” 

Again, the standard JS library gives two constants within which we can safely perform calculations.

 

Number.MAX_SAFE_INTEGER < 9999999999999999
Number.MIN_SAFE_INTEGER > -9999999999999999

 

In the example, you can see that going beyond them isn’t a great idea if you want accurate calculations.

 

0.2 + 0.1 !== 0.3 but 0.5 + 0.1 === 0.6

 

Here’s another quirk of JavaScript that seems super weird. But in actual fact, this is not so much the fault of the language. It’s more a problem with how numbers are written in binary. Fortunately, there is a way to deal with this. 

You just need to enter results with a reasonable number of decimal places.

 

Math.max() === -Infinity and Math.min() === Infinity

 

This takes us onto the real question: what are these two functions? Their task is to select the largest and smallest number from a given set of numbers as arguments in turn.

What’s wrong with the Object and Array?

 

[] + [] === “”

 

And you guessed it — now we enter even more weirdness. If you recall your first JavaScript course, tutorial, or book, we bet it said something like ‘JS is a dynamically typed language’. But what does that mean in practice? 

In short, it means we shouldn’t worry about the type of variable. We should only assign a value to it, then let the JS engine determine the type we are dealing with.

 

let a = 124;
let b = 'meow';
typeof a // number
typeof b // string

 

How does JS do this? By using something called the “duck typing” mechanism. The following quote paints a nice picture of how this works:

‘If it looks like a duck and quacks like a duck, it must be a duck.’

OK — nice quote: but how does it relate to the example? 

Well, it just so happens that arrays in JS cannot be added together with the + operator. However, we can combine two text strings this way. Meaning a smart JS engine can project arrays onto empty strings dynamically, then join them together. And the output is an empty string.

 

[] + {} === ‘[Object object]’

 

Again, the result may surprise you. But the principle actually reflects the previous example. As we know, an array cannot be added to something, so it is converted to an empty string. As a result, the object is also converted to a string.

The following example is what the textual representation of an object might look like:

 

 String({})

 

{} + [] === 0

 

OK, if you’ve managed to stick with us until now, you’re doing great. But the next part could be the final straw. Because you might now be wondering, ‘But why is the addition not commutative?’ When, in actual fact, it is! 

Just remember that previously, we did not add. Instead, we combined (concatenated) two strings of characters. ‘So are we adding now?’ you ask. Well, of course not! That would be too easy. This plus sign changes the empty array to a number here.

.

+ '27' // 27
!! 1   // true
'' + 777 // '777'


If you didn’t know the magic of these methods, now you do. And we’re sure you’ll find them helpful to avoid having to write casting functions.

Still, you might feel there’s a little weirdness lurking somewhere. And that’s because we still have this empty object. But, surprise, surprise, JS has tricked you once again! It just so happens that {} is not only used to signify an empty object.

Sometimes, it’s used to declare a block of code. And at this point, the parser treats it as an empty code block that does absolutely nothing. 

Consequently, it’s ignored for this operation.

The truth, the whole truth, but is it really the truth?

 

true + true + true === 3 and true-true === 0

 

As is the case with most programming languages, true is equated with the number 1. Therefore, no one should be surprised that 3 * true gives us 3. And the same goes for `1 – 1 === 0.

 

true == 1 but true !== 1

 

Here, you should understand the difference between the ‘equality’ == and ‘identity’ === operators. The identity operator does not allow implicit type coercion. And as a result, true (which is a boolean type) cannot become 1 (a number).

 

(!+[]+[]+![]).length === 9

 

That might have your head in a bit of spin, so to cheer you up, know that only a few things will ever truly surprise you in programming. But to understand this, you have to break the parenthetical expression into pieces once again.

It will be easier to explain what mechanisms take place here if we consider this expression from the end, so let’s do that:

  • ![] – gives false. Why? An array is really an object, not a simple type. Any object cast to boolean returns true. Hence, the denial of true gives us false.
  • []+![] is the same as []+false. It converts an empty array to an empty string. The result of this expression is, therefore, 'false' as a string.
  • !+[] – a + here doesn’t mean addition, but casting the array to a number, so the result will be 0, and if we deny zero, we’ll get true.
  • This way, we arrived at the most simplified version of the parenthesis. It looks like this: (true + 'false'), which results in string concatenation, i.e. 'truefalse'. The length of the starting string is 9.

 

Now we’ve been through much of the weirdness of JavaScript, we hope you’re learning to love it as much as we do. And if you feel we’ve missed something — or if you have a question for the team — feel free to share your thoughts on Twitter or LinkedIn.

 

______

This article was originally published in Polish on my personal blog.

Kornelia Kobiela

JavaScript Developer at DLabs.AI, blogger, and open source contributor. Believes that technology can help us build a more sustainable and inclusive world.

Read more on our blog