Mischievious JS (2 Part Series)
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.
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
max() as negative, I find an explanation very convincing...
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.
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.
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:
- You did an operation not explained by Math. Example- 0/0, Infinity/Infinity, Infinity * 0
- You are trying to convert a non-numeric value to Number.
- 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.
let x = NaN; isNaN(x); //true
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?
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:
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:
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 = 90; x = 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:
AMAZING!!! Isn't it?
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! 👋