Cowboy Bebop Vicious
Cowboy Bebop Vicious
Cowboy Bebop Vicious
Cowboy Bebop Vicious
Cowboy Bebop Vicious

JavaScript Quirks

By Sebastian Pennino

A strange pixelated portrait of a developer
Presentation logo

By Sebastian Pennino

Warning

The following presentation may contain:

  • Code examples 🧻
  • Dad jokes 🤡
  • Material that can be considered more recreational than useful (curiosities)
  • References to stuff that happened 10+ years ago 👴
  • Me trying to cover too much stuff in 30 minutes

Act 1: Brief JS history

Javascript Creation

Brendan Eich, creator of javascript
Brendan Eich (picture taken while staring directly at the sun)

On November 5, 1955, Brendan Eich was hanging a clock while standing on his toilet. The porcelain on the toilet was wet and he slipped, hitting his head on the sink, when he woke up he wrote what he saw in a piece of paper...

The real story

On Sept 1995, Brendan was asked by Netscape Communications to design a versatile programming language that could speed up web development and serve as a scripting companion for Java. He did it in 10 days. The original purpose was:

  • It will give Netscape Navigator and 'edge' over IE
  • Easy to use and learn
  • To work in the browser for "animations and effects" (to be used by designers)
  • Don't block the user / browser when there's errors

Act 2: Cases

Starting on the next slide we will be discussing individual cases. I will present an example and we will discuss the outcome

Finally some code!

              
              // Case 1
              const a = [10, 10, 10, 10].map(parseInt)

              // Case 2
              const b = 0.1 + 0.2

              // Sebas: press U for fun
              
            
              
                a -> [10, NaN, 2, 3]
                b -> 0.30000000000000004
              
            

...?

              
              // Case 1 
              const a = [10, 10, 10, 10].map(parseInt); // -> [10, NaN, 2, 3]
              
            
                ParseInt:
                parseInt(string[, radix])
              
                Array.prototype.map:
                (callbackfn, thisArg?: any): any[]
              
                The callbackfn:
                (value: number, index: number, array: number[]) => any
              

IMO in this case there's no Javascript quirk perse. This might be a misusage (due to unfamiliarity) with the parseInt function and the map method

              
                // Case 2
                const b = 0.1 + 0.2; // -> 0.30000000000000004
              
            

When JS was designed it was decided that all numbers should have the same representation

So instead of having Integers, floats, signed, unsigned, etc we only got a 32-bit floating point representation for all numbers

There's a long explanation (here) that requires understanding binary but in a nutshell its a rounding error of the numeric representation, you can reproduce this error on any language that uses the 32-bit floating point representation

Converting values

Act 3: Converting Values

Converting a value from one type to another is often called "type casting," when done explicitly, and "coercion" when done implicitly (forced by the rules of how a value is used).

However, in JS, most people refer to all these types of conversions as coercion, so the way I prefer to distinguish is to say "implicit coercion" vs. "explicit coercion."

            
              const a = 42;
              const b = a + "";       // implicit coercion
              const c = String( a );  // explicit coercion

              const value1 = '6';
              const value2 = 3;
              let sum = value1 + value2;
    
              console.log(sum); // what will log?
            
          
it will log: '63' // jelinek

Logical NOT (!)

In javascript, a truthy value is a value that is considered true when encountered in a Boolean context. Also, all values are truthy unless they are defined as falsy

Falsy values are: false, 0, -0, 0n, "", null, undefined, NaN

0 (zero) and one have a special place in javascript, if you often minify your code, you will find that any true and any false in the code will be transpiled to !0 and !1 respectively (to save 2 and 3 characters!). (Online minifier https://codebeautify.org/minify-js)

Unary plus (+) | Addition

This simple character has different functions: precedes its operand and evaluates to its operand but attempts to convert it into a number, if it isn't already.

Otherwise produces the sum of numeric operands or string concatenation


                +true  // -> 1
                +false // -> 0
                +null  // -> 0

                // Number + Number -> addition
                1 + 2 // -> 3

                // Boolean + Number -> addition
                true + 1 // -> 2

                // Boolean + Boolean -> addition
                false + false // -> 0

                // String + String -> concatenation
                'foo' + 'bar' // -> "foobar"

                // Number + String -> concatenation
                5 + 'foo' // -> "5foo"

                // String + Boolean -> concatenation
                'foo' + false // -> "foofalse"

              

toString() method

All the different natives have a toString method that will be used implicitly by javascript

  • String.prototype.toString()
  • Number.prototype.toString()
  • Boolean.prototype.toString()
  • Object.prototype.toString()

Note: there's also toNumber, and toBoolean, but we kinda cover those.

Act 4: Advanced coercion examples

Now that we have some tools let's dive in

true is what?


                'true' == true // false
                false == 'false' // false
              

                'true' == true
                ==> NaN == 1
                ==> false
                
                false == 'false'
                ==> 0 == NaN
                ==> false

                == operator triggers numeric conversion, 
                string 'true' is converted to NaN, 
                boolean true is converted to 1.
              

fooNaN / baNaNa


                ("foo" + + "bar") === "fooNaN" // true

                "b" + "a" + +"a" + "a"; // -> 'baNaNa'
              

Explanation

                
                  "foo" + + "bar" 
                  ==> "foo" + (+"bar") 
                  ==> "foo" + NaN 
                  ==> "fooNaN"

                  Unary + operator has higher precedence over binary + operator. 
                  So +'bar' expression evaluates first. 
                  Unary plus triggers numeric conversion for string 'bar'.
                  Since the string does not represent a valid number, the result is NaN. 
                  On the second step, expression 'foo' + NaN is evaluated.
                
              

Adding arrays


                [1, 2, 3] + [4, 5, 6]; // -> '1,2,34,5,6'
              

              // The concatenation happens. Step-by-step, it looks like this:             
              [
                // call toString()
                (1, 2, 3)
              ].toString() +
              [4, 5, 6].toString();

              // concatenation
              "1,2,3" + "4,5,6";
              
              // ->
              ("1,2,34,5,6");
              

[] is equal ![]


                [] == ![]; // -> true
              

              // Here is how this expression simplifies. Step-by-step:
              +[] == +![];
              0 == +false;
              0 == 0;
              true;
              

Act 5: Other quirks

  • Array are not-so-secretly objects
  • Hoisting
  • Argument (Array.prototype.slice.call(arguments))
  • Accesing prototype using __proto__
  • Curiosity: JS F*** (http://www.jsfuck.com/)

The end

end

Sources:

  • JS Fuck "esoteric and educational programming style" http://www.jsfuck.com/
  • Online minifier https://codebeautify.org/minify-js
  • JavaScript data types and data structures https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures
  • WTF JS https://github.com/denysdovhan/wtfjs and https://wtfjs.com/
  • Abstract-equality-comparison https://262.ecma-international.org/11.0/#sec-abstract-equality-comparison
  • Brian Leroux - WTFJS (dotconferences.eu - Nov 30th, 2012) https://www.youtube.com/watch?v=et8xNAc2ic8
  • Gary Bernhardt - WAT (from CodeMash 2012 - Jan, 2012) https://www.destroyallsoftware.com/talks/wat
  • JavaScript type coercion explained - https://www.freecodecamp.org/news/js-type-coercion-explained-27ba3d9a2839
  • You don't know JS - Types & Grammar ch 1 types - https://www.oreilly.com/library/view/you-dont-know/9781491905159/ch01.html
  • You don't know JS - Types & Grammar ch 4 coercion - https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/types%20%26%20grammar/ch4.md#chapter-4-coercion