loading...

Little Shenanigans of JavaScript #2

salyadav profile image Saloni Yadav ・6 min read

Mischievious JS (2 Part Series)

1) Little shenanigans of JavaScript 2) Little Shenanigans of JavaScript #2

JavaScript is like the father who over-pampered and spoilt his son, and now the son blames his Dad for things he can't handle. When I was first introduced to JS, I was said, and I quote - "JavaScript is a very forgiving language." This epithet stuck with me forever. Indeed, JS lets you do stuff you cannot imagine with other popular languages (I do not speak for the ones I don't know).

Alt Text

But before blaming JS think for a second, WHY would you want to add a string and number? What's the meaning of subtracting two strings? Why would you want to assign a negative index in an array? (Wait, did I just say negative indices??👻 Boo! I will get to it.) Some of the answers are obvious to ardent JS users when they use it day-in and day-out. But for the rest of you out there, just don't do it until you see why!

Jokes aside, I present to you few more such playful insanities of JS. I had a fun time fiddling with them, hope you too. Enough said, let's dive in.

1. Math.min() and Math.max() Upside-down

Most of us use these two functions in day-to-day basis. It's easiest way to compare a set of N numbers. Let's see what happens when you call them without feeding any parameters. What do you think the output to the following be:

console.log( Number.POSITIVE_INFINITY > Math.min() ); //false
console.log( Number.NEGATIVE_INFINITY < Math.max() ); //false
//Damn Son!!

First reaction: You kidding me!
But let's go ahead and see what values are we comparing at first place.

console.log( Math.min() ); //Infinity
console.log( Math.max() ); //-Infinity

Although this feels very counterintuitive to have min() as +Infinity and max() as negative, I find an explanation very convincing...

Let's take Math.min().
We use it to find the minimum number from a set. When you call it with no parameters, it initializes a number with Maximum Possible Value. Then, when you compare your first finite number with this, it will always pick that number as minimum.
Imagine if Math.min() was -Infinity. No matter what you compare this with, it will always pick your -Infinity. The function would fail!

When I have to write an algorithm to find a minimum of something. Say, a minimum Sum, or the smallest number in a dynamic array, or what-so-ever, I always initialize my comparison variable with Math.min(), so when I revisit it, I instantly know what I am intending to do! That is, find the MINIMUM.

Doesn't sound so counterintuitive now, does it? Simple logic- Want to find the minimum of a lot? Initialize using min!

Needless to explain, the same logic goes with Math.max(). To check if a number is maximum, we start comparing it with -Infinity and climb all the way up.

Now that you know, you will find yourself using this so very often! Been there. Done that.

2. Identity Crisis of NaN (I am Not-A-Number!!)

What do you think is the type-of NaN?

console.log( typeof NaN );
//"number"

This one got me rolling on the floor. 🤣
Literally, the full-form of NaN is Not a number. And yet, here we are!

Contrary to the popular belief, NaN is not a JS Keyword. It is merely a property of the global object Number, just like several others you would be aware of:

let x = Number.NaN; //NaN
let y = Number.NEGATIVE_INFINITY; //-Infinity
let z = Number.MIN_VALUE; //5e-324
let w = Number.MAX_VALUE; //1.7976931348623157e+308

NaN signifies quite a variety of scenarios. To enumerate a few:

  1. You did an operation not explained by Math. Example- 0/0, Infinity/Infinity, Infinity * 0
  2. You are trying to convert a non-numeric value to Number. Example- Number('foo') or +"foo"
  3. You challenged the finites of Computer Arithmetic and executed an operation far bigger than the bits could hold. Example- (3.3489324884 * 10e616) / (3.3489324884 * 10e616); //NaN

So, NaN does not always signify Not-a-number, rather it's a way of saying-
"You are trying to get a number beyond the understanding of your machine."

having understood NaN now, what would be output for this:

let x = (3.454*10e500)/(3.454*10e500);
console.log( x );
console.log( x === NaN );

YES! Although x is NaN, the comparison throws False. Could you try reasoning out why?
This question reminds me of a famous John Green quote:
"Some infinities are bigger than other infinities."

Anyways, if you are searching for an exact answer why this doesn't work and how else will you check for NaN, you will find the answer here.

Shhh, spoiler:

let x = NaN;
isNaN(x); //true

3. Who murdered my Array?

Prepare to get Bonkers! I urge you to open your Developers Console even before you start scrolling, you are going to need it.

let x = [10, 20, 30, 40, 50];
console.log( x.length );

x[-1] = 0;
x[-2] = -10;
console.log( x.length );
console.log( x );

Did JS just let me add negative indices to an array!!! 🔪🔪🔪

Before I start explaining, let's see what the output looks like?

Alt Text
Alt Text

If you notice, even after adding two more data to the array, x.length remains as 5, although the array shows the newly added data.

Let's get our funda clear-

Any non-primitive data type in JS is treated as an Object. Let alone Arrays, Sets, Maps, even Functions are Objects. And any object is a set of key-value of pairs.

To understand what's happening in our use case here, let's for a second, forget that x is an Array, and treat it as an Object (which it is, since arrays are also objects). Now, let's try adding a function definition, or a new attribute to x:

x.foo = () => console.log('in x foo')
x.name = "James Dean";
console.log( x );
console.log( x.length );

x.foo();
console.log( x["name"] );

I hope you are trying this out on-hands with me. You will get an x that looks like this:

Alt Text

Are you able to guess what's happening? The array length still remains as 5 but all other attributes are present just like in an Object. If you open up the __proto__ of x you will see Array, open it up one more hierarchy and you see Object. This is Prototype Chaining.

Since, only whole number indices are supported by the Array data structure, the rest of the keys are simply treated as key-value pairs of an Object.

You can simply invoke foo using x.foo() or access the name attribute using one of the two ways of accessing a JSON Object:

  1. x.name
  2. x["name"]

So what's with the negative indices?

They are also just a key-value pair like name. Where the object x has
x["-1"] attribute value. It is only an illusion of negative index where as it's only a part of the x object and not the Array.

And there's your answer!!! 🦄

But before I end, I want you to try a couple more things and see what x looks like and what happens to the length:

x[5] = 90;
x[8] = 100;
//NOTE: We skipped index 6 and 7 altogether.
//What happens to the length?

console.log( x.length ); //9
console.log( x );

When you skip the whole number indices (the legit indices of an array), JS just creates EMPTY spaces- an array index holding undefined data type. But the space gets reserved as a part of the array. And that's why the length increases to the maximum index. This is what it looks like:

Alt Text

AMAZING!!! Isn't it?

I absolutely adore JavaScript for it's Willy Wonka ways with data types and data structures. I have laughed out loud at some problems, I have pulled my brains out at others. But nevertheless, I hope this language never dies. Frameworks may come and frameworks may go, I hope Vanilla JS goes on forever.

I do hope you had fun trying out some examples from above. And I also hope, I atleast inspired a handful of you to open up your computers and get scripting! Do let me know if I went wrong somewhere or what you think about the article. Your response inspires me to write more! 🧐

Find the previous article of this series here.
See you soon! 👋

Mischievious JS (2 Part Series)

1) Little shenanigans of JavaScript 2) Little Shenanigans of JavaScript #2

Posted on May 15 by:

salyadav profile

Saloni Yadav

@salyadav

I am a believer of the Root Cause Analysis. Ask "How, What, Why" until you can dissect it with no further to go. Well, I am a frontend developer ready for new challenges!

Discussion

markdown guide