JavaScript quirks in one image from the Internet
Tags: javascript
Published: 2019-03-01 16:55:46

Recently I stumbled upon this picture on Google Images:


![Thanks for inventing JavaScript](https://thepracticaldev.s3.amazonaws.com/i/4n583bhdqnz03mq3t13v.png)


The man on the picture is Brendan Eich by the way, the creator of JavaScript and a co-founder of the Mozilla project.

Even with some of the examples are not really related to the language itself, I still find it interesting enough to give it a short breakdown, considering it doesn't make much sense for some people with the classic "strict language"-only programming background.

## The breakdown

Starting with the "boring" parts:

#### Floating-point arithmetic

```
> 9999999999999999
< 10000000000000000

> 0.5+0.1==0.6
< true

> 0.1+0.2==0.3
< false
```

Nothing really surprising here, it's an old concept that has been around for quite a while. And it is, of course, not related to JavaScript "features". Instead of trying to explain it here, I'll just leave a link the to [this great](https://floating-point-gui.de/) "explainlikeimfive" website dedicated exclusively to explaining floating-point math.


#### Not A Number is a Number

```
> typeof NaN
< "number"
```

What is "NaN" after all? It is, in fact, a representation of a specific value that can't be presented within the limitations of the numeric type (the only JS numeric primitive is, in fact `float`). NaN was introduced in the IEEE 754 floating-point standard. 

So, it's just a number that a computer can't calculate in this particular environment. 

#### Type conversion

JavaScript is a dynamic type language, which leads to the most hated "why it this like that" debugging sessions for those who is not familiar with the silent (implicit) type coercion. 

The simple part: strict equality with `===`

```
> true === 1
< false
```

Strict equality compares two values. Neither value is implicitly converted to some other value before being compared. If the values have different types, the values are considered unequal. Boolean variable is not equal to 1, which is a number.

On the other hand, there is this:

```
> true == 1
< true
```
 
This is an example of _implicit type coercion_. Implicit type coercion is being triggered when you apply operators to values of different types: `2+'2'`, `'true'+false`, `35.5+new RegExp('de*v\.to')` or put a value into a certain context which expects it to be of a certain type, like `if (value) {` (coerced to `boolean`).

JavaScript type conversion is not the most trivial part, so I would suggest further reading like [this great article](https://medium.freecodecamp.org/js-type-coercion-explained-27ba3d9a2839) by Alexey Samoshkin and [this little MDN doc](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Equality_comparisons_and_sameness) on equality comparisons. There is also this [equality comparison cheatsheet](https://dorey.github.io/JavaScript-Equality-Table/) that may come in handy. 

Anyway, let's get back to our picture.


```
> [] + []
< ""
```

There are 2 types of variables in JS: objects and primitives, with primitives being `number`, `string`, `boolean`, `undefined`, `null` and `symbol`. Everything else is an object, including functions and arrays.

When an expression with operators that call implicit conversion is being executed, the entire expression is being converted to one of three primitive types:

- string
- number
- boolean

Primitive conversions follow certain rules that are [pretty straightforward](https://www.w3schools.com/js/js_type_conversion.asp).

As for the objects: In case of `boolean`, any non-primitive value is always coerced to `true`. For `string` and `number`, the following internal operation [ToPrimitive(input, PreferredType)](https://tc39.github.io/ecma262/#sec-toprimitive) is being run, where optional `PreferredType` is either `number` or `string`. This executes the following algorithm:

1. If input is already a primitive, return it as it is
2. Otherwise, input is treated like an object. Call `input.valueOf()`. Return if the result is a primitive.
3. Otherwise, call `input.toString()`. If the result is a primitive, return it.
4. Otherwise, throw a TypeError.

Swap 2 and 3 if `PreferredType` is `string`.

Take a look at this pseudo-implementation of the above in actual JavaScript, plus the boolean conversion (the original is a [courtesy of Alexey Samoshkin](https://gist.github.com/samoshkin/baf070ab19b73f4f39ec54149fb37c30#file-js-to-primitive-internal-js) via the article mentioned previously). 

```js
function ToPrimitive(input, preferredType){
  
  switch (preferredType){
    case Boolean:
      return true;
      break;
    case Number:
      return toNumber(input);
      break;
    case String:
      return toString(input);
      break
    default:
      return toNumber(input);  
  }
  
  function isPrimitive(value){
    return value !== Object(value);
  }

  function toString(){
    if (isPrimitive(input.toString())) return input.toString();
    if (isPrimitive(input.valueOf())) return input.valueOf();
    throw new TypeError();
  }

  function toNumber(){
    if (isPrimitive(input.valueOf())) return input.valueOf();
    if (isPrimitive(input.toString())) return input.toString();
    throw new TypeError();
  }
}
```

So, at the end of the day, the original `[] + [] == ""` is being interpreted as:

```js
ToPrimitive([]) + ToPrimitive([])
``` 

Both arrays return an empty string as a result of `toString([])`. The final result is a  concatenation of two empty strings.  

Now, onto the:

```
> [] + {}
< "[object Object]"
```

Because of the `String({})` resulting in a `[object Object]` the result is a simple concatenation of `""` and `"[object Object]"`. Simple enough. Now what the hell is going on here then?

```
> {} + []
< 0
```

Turns out, JavaScript interprets the first `{}` as a code block! When the input is being parsed from start to end, it treats `{` as the beginning of the block, following by closing `}` immediately. Hence, using our pseudo-implementation the previous example will be evaluated into the following:

```js
ToPrimitive(+[])
```

..which is 0. The `+` is an unary prefix operator that converts the operand into a number. 

Loose equality `==` and binary `+` operators always trigger default `preferredType`, which assumes numeric conversion (except Date that returns string). That explains `true+true+true===3` and `true==1`. Thus, as expected `true===1` returns `false` because there are no operators on the left side of the expression and `===` does not trigger implicit type coercion. Same with `[]==0` which is roughly equivalent to `Number([]) == 0`.


Everything brings up interesting examples like the one we have here:

```
> (!+[]+[]+![]).length
< 9
```
Breaking it down,

 - (!+[]) + [] + (![])
 - !0 + [] + false
 - true + [] + false
 - true + '' + false
 - 'truefalse'

'truefalse'.length === 9 

Very simple.

And last (and the least, to be honest):

#### Math.max() < Math.min() ?

```
> Math.max()
< -Infinity
> Math.min()
< Infinity
```

This _may_ be considered as a minor language flaw, in terms of returning a kind of an unexpected result from a function that wants certain arguments. 

But there actually is a little bit of some actual math behind that. 

Let's make a guess on how (probably) `Math.max()` works and write down another imaginary transcript into actual JavaScript:

```js
Math.max = function () {
  let temp = -Infinity;
  for ( let i = 0; i < arguments.length; i++ ) {
    let num = Number(arguments[i]);
    if ( num > temp ) {
      temp = num;
    }
  }
  return Number(temp);
}
```

Now it kind of makes sense to return `-Infinity` when no arguments are passed. 

`-Infinity` is an [identity element](https://en.wikipedia.org/wiki/Identity_element) of `Math.max()`. Identity element for a binary operation is an element that leaves any other element unchanged after applying said operation to both elements.

So, 0 is the identity of addition, 1 is the identity of multiplication. `x+0`and `x*1` is always `x`. Out of `-Infinity` and `x`, `x` will always be the maximum number.

There is an absolutely [gorgeous article](https://charlieharvey.org.uk/page/why_math_max_is_less_than_math_min) by Charlie Harvey that deeply dives into this topic.

---


Summing up, implicit type coercion is a very important concept you should always keep in mind. Avoid loose equality. Think about what are you comparing, use explicit conversion whenever possible. Consider switching to TypeScript if the above scares you :)

And if you want to see more "wtf" JavaScript, there is a great resource called, literally, [wtfjs](https://github.com/denysdovhan/wtfjs), that is also available as a handbook via `npm`.