All Articles

Javascript is weird?

Jul 30, 2020


I recently stumbled on a tweet about some of the things considered weird in Javascript. I decided to write this post to share some of the reasons why this things are in javascript.

https://twitter.com/Ashot_/status/1287818215465324546?s=20

Understanding why they are, will lead to less confusion about the way the language handles operations across several data types. Some of these weirdness happen because Javascript is a loosely typed language, which isn't bad in itself but it just means you should be careful the way you use operators and not to always assume.

  1. Why is the typeof NaN === 'number'?

    NaN stands for Not a Number but suprisingly has a type, number.

    This is one thing I considered weird when I started writing Javascript.

    I understood why that is after reading an article on Ire Aderinokun's blog, I quote from her blog:

    The type of NaN, which stands for Not a Number is, surprisingly, a number. The reason for this is, in computing, NaN is actually technically a numeric data type. However, it is a numeric data type whose value cannot be represented using actual numbers. So, the name "Not a Number", doesn't mean that the value is not numeric. It instead means that the value cannot be expressed with numbers.

  2. Why is 9999999999999999 converted to 10000000000000000 in JavaScript?

    Javascript doesn't have integers. 9999999999999999 is treated internally as a floating point number and at this point has ran out of floating-point precision.

    Someone explained it beautifully on StackOverflow here.

  3. 0.1 + 0.2 !== 0.3

    I remember having a chat with Michael about this some months back. I was literally pulling my hair and cursing because it didn't make any sense to me. I decided to research more about it and I found a really helpful explanation here.

    A number is stored in memory in its binary form, a sequence of bits – ones and zeroes. But fractions like 0.1, 0.2 that look simple in the decimal numeric system are actually unending fractions in their binary form.

    In other words, what is 0.1? It is one divided by ten 1/10, one-tenth. In decimal numeral system such numbers are easily representable. Compare it to one-third: 1/3. It becomes an endless fraction 0.33333(3).

    So, division by powers 10 is guaranteed to work well in the decimal system, but division by 3 is not. For the same reason, in the binary numeral system, the division by powers of 2 is guaranteed to work, but 1/10 becomes an endless binary fraction.

    There’s just no way to store exactly 0.1 or exactly 0.2 using the binary system, just like there is no way to store one-third as a decimal fraction.

    The numeric format IEEE-754 solves this by rounding to the nearest possible number. These rounding rules normally don’t allow us to see that “tiny precision loss”, but it exists.

    Understanding the floating point arithmetic is very crucial to understanding why this is.

    console.log((0.1).toFixed(20)); // 0.10000000000000000555
    
    // And when we sum two numbers, their “precision losses” add up.
    
    // That’s why 0.1 + 0.2 is not exactly 0.3.
    
    console.log(0.1 + 0.3); // 0.30000000000000004
    
  4. Math.max() === -Infiinity and Math.min() === Infinity

    Weird right?

    The question I asked myself when I saw this is, what exactly does Math.max() do?

    I initially confused it with Number.MAX_VALUE which represents the maximum numeric value representable in JavaScript. Values greater than Number.MAX_VALUE are represented as Infinity.

    Infinity > Number.MAX_VALUE; // true
    

    Math.max is a function that returns the largest of the zero or more numbers given as input parameters, when we call Math.max() we pass in no arguments.

    Math.max(1, 4, 2); // 4
    
    Math.min(2, 1, 3); // 1
    
    Math.min(1); // 1
    

    When we pass in just 1 into the Math.min function, the function returns 1 because that's the sole value passed into the function. Internally, the function needs something to compare values passed into it against, like a starting value, let's call this an Identity variable.

    These articles might help make things clearer:

  5. [] + [] == ""

    Adding two arrays returns an empty string, this happens because the + operator only exists for strings and numbersin javascript. When you try to add two arrays, Javascript tries to convert the array into a string by extracting the content of the array and converting it to a string, if the array is empty then it defaults to an empty string, hence why [] + [] == "".

    [] +
      []['bol'] + // ""
      ['aji'][('bo', 'la')] + // 'bolaji'
      ['ji']; // bo,laji
    

    Javascript is basically calling the toString method on the array prototype and concatenating the result.

  6. [] + === '[object Object]'

    From our understanding of the way the addition operator works so far we know the operator works mainly with strings and numbers. We can convert an array to a string using the toString method that exists on the Array prototype.

    var arr = ['bol', 'aji'];
    console.log(arr.toString()); // 'bol,aji'
    
    // we can also coerce it into a string using the `String` method in javscript
    console.log(String(arr)); // 'bol,aji'
    

    However, when we try to coerce an object the result is '[object Object]' and that's why [] + {} is equal to '[object Object]'.

    var arr1 = [];
    var arr2 = ['proton'];
    var obj = {};
    
    console.log(arr1 + obj); // '[object Object]'
    console.log(arr2 + obj); // 'proton[object Object]'
    
  7. + [] === 0

    Since coercing objects and arrays to their string equivalent is what happens when we use the addition operator on them, it's weird that adding an array to an object returns a value of 0 which is a number. This is because the curly brace "{" is a very important character in Javascript used to denote the beginning of a statement block.

    When a statement begins with "{" in Javascript, it's usually interpreted as a block. Since the statement begins with an empty block, the interpreter assumes nothing is happening and goes on to evaluate + [], because the statement now starts with the addition operator, it coerces the array into a number type.

    Number([]); // 0
    Number(['proton']); // NaN
    

    Check out this StackOverflow answer.

  8. Booleans are evil numbers?

    true + true + true; // 3
    true - true; // 0
    true == 1; // true
    true === 1; // false
    

    The addition operator + used here forces Javascript to coerce the boolean values into numbers because + is primarily meant for numbers.

    Number(false); // 0
    Number(true); // 1
    
    true + true + true; // 1 + 1 + 1 = 3
    true - true; // 1 - 1 = 0
    

    The == operators compares two values regardless of their type - since the numerical representation of true is 1 that's why true == 1 returns true. However, the === compares the types of the two values and that's why true === 1 returns false.

  9. [] == 0 returns true

    This is also because of the way the == operator works.

    The == version of equality is quite liberal. Values may be considered equal even if they are different types, since the operator will force coercion of one or both operators into a single type (usually a number) before performing a comparison. - Source

    According to ECMA, here's the way the == operator works when x == y.

    ECMA's definition of how == works

    According to the image above, when comparing [] == 0, we'd need to convert the array [] into it's primitive type, I don't want to dwell too much on primitives because it's a big topic on it's own but if you go through this post here you will be able to figure that the primitive type of an array is the value of .toString, which in our case is an empty string.

    At this point, we've been able to reduce the comparison to "" == 0, according to the spec above, when you compare a string and a number with the == operator, the result will be the result of coercing the string into a number and comparing the two numbers.

    [] == 0;
    // when you convert the empty array to it's primitive type using [].toString()
    // the result is an empty string
    Number(''); // 0
    0 == 0; // true
    
  10. 9 + "1" = "91' but 91 - "1" = 90

    This is absolutely normal (for a loosely-typed language, obviously) because the addition operator can be used on strings while the subtraction operator can't.

    When you add a string to a number, Javascript coerces the number into a string, then concatenates the both of them.

    9 + '1';
    // Javascript coerces the number into a string
    '9' + '1';
    
    // then after normal string concatenation we get
    ('91');

    However, because subtraction isn't a valid operator for strings, Javascript coerces the string into it's number equivalent.

    // since subtraction isn't a valid operator for strings
    91 - '1';
    // Javascript coerces the string into a number
    91 - 1;
    // the result of the subtraction between the two numbers return a number
    90;

If this was helpful, feel free to share and/or drop a comment.

If you’ve got questions, feel free to share them in the comment section or reach out to me on twitter.

You may also want to check out this post by Toptal about the most common mistakes that many JavaScript developers make.


Next

Setting up MySQL on a Mac