7 Things You May Not Know in JavaScript

• 4 minutes READ

There is a lot of fun to be had when working in JavaScript. Even for developers that interact with it daily, some parts of the language remain unexplored. I’m going to highlight seven things you may not know about JavaScript.

Note: I am going to use ES2015 in the examples: pretty much the let keyword (you can replace it with var if you don’t have an interpreter with ES2015 support) and arrow functions. Alternatively, you can babelify the code automagically.

7 Things You May Not Know in JavaScript

1. There Are Two Zeros

Usually, we use the positive value of zero. But there is a -0 as well! Because of the way how they are stringified, you won’t see them in the console:

+0
→ 0

-0
→ 0

That’s because both (-0).toString() and (+0).toString() return 0.

Going a bit deeper, we find out that they are actually equal:

No-Code Email Template Builder

With Postcards Email Builder you can create and edit email templates online without any coding skills! Includes more than 100 components to help you create custom emails templates faster than ever before.

Free Email BuilderFree Email Templates
+0 === -0
→ true

+0 > -0
→ false

+0 < -0
→ false

Also, if we try to use indexOf over arrays that’s not going to help too much (since indexOf does use strict equal: ===):

// We would expect 1, right?
[+0, -0, 42].indexOf(-0)
→ 0

[-0, +0, 42].indexOf(+0)
→ 0

There is a way, actually, to find out if a value is negative zero: by dividing a positive and finite number to that value:

42 / 0
→ Infinity

42 / -0
→ -Infinity

So, we can simply say:

// Two conditions:
//   1. The input parameter should be zero (negative or positive)
//   2. Dividing a number by that input, we should get a negative value (-Infinity)
let isNegativeZero = input => input === 0 && 1 / input < 0;

// Let's test it
isNegativeZero(0)
→ false

isNegativeZero(+0)
→ false

isNegativeZero(-0)
→ true

2. NaN (Not a Number) Is a Special Number

Yes, NaN is a number:

typeof NaN
→ "number"

Thre are a few ways we can obtain it:

  • 0 / 0 (divide 0 by 0)
  • +’foo’ (convert a non-number string into number)
  • Infinity – Infinity
  • …and many more.

Truth is that it is a special number.

NaN does not equal itself.

If you ever saw a thing like if (x !== x) {…}, now you’ll understand what was going on there.

In short, NaN does not equal NaN!

Low-Code Website Builders

With Startup App and Slides App you can build unlimited websites using the online website editor which includes ready-made designed and coded elements, templates and themes.

Try Startup App Try Slides AppOther Products
NaN === NaN
→ false

// Even by storing the value in a variable
let x = NaN
x === x
→ false

A side effect is that you’ll never use indexOf if you want to find out the index of a NaN value into an array:

let values = [7, NaN, 42];

// Find the index of 42
values.indexOf(42);
→ 2

// Find the index of NaN (WRONG!)
values.indexOf(NaN)
→ -1


// If you really want to find the index of NaN, simply create your indexOf function
let myIndexOf = (arr, value, start) => {
  if (value !== value) {
    start = start || 0;
    for (let i = start; i < arr.length; ++i) {
       if (arr[i] !== arr[i]) {
          return i;
       }
    }
    return -1;
  }
  return arr.indexOf(value, start);
};

// Now, it will work!
myIndexOf(values, NaN)
→ 1

Note you can use isNaN(x) instead of checking if x !== x to find out if x is NaN, but that’s a little bit slower.

But why is that? The easy answer is that this behaviour is dictated by IEEE 754:

Every NaN shall compare unordered with everything, including itself.

Tip: If you’re using ES2015, includes handles the NaN case:

[42, NaN].includes(NaN)
→ true

NaN is not (in)finite.

NaN is not a finite number. That does not mean it is infinite. It’s simply not finite or infinite.

// Check if it's finite
isFinite(NaN)
→ false

// Comparing with infinity, it will always give us false
Infinity > NaN
→ false

> Infinity < NaN
→ false

-Infinity < NaN
→ false

> -Infinity > NaN
→ false

NaN is neither positive or negative.

NaN is NaN. There are no +NaN or -NaN. Both are NaN:

NaN
→ NaN

-NaN
→ NaN

+NaN
→ NaN

3. Use of Bitwise Operators

This is quite language-agnostic, but since the bitwise operators are supported in JavaScript I’m going to show you some nice stuff using them.

Fast multiplication/division of integers

The use-case could be when you want to render some complex 3D animation on a big canvas. You want to generate and render the frames as quick as possible. Let’s assume you need some math there (surely you do).

When you want to multiply/divide something by 2, 4, 8, 16 or any other power of 2, the trick is to use the bitwise operators which move the bits of the numbers to the right (division) or to the left (multiplication).

// Same with 21 * 2, but faster
21 << 1
→ 42
 
// Same with 5 * 4
5 << 2
→ 20

The << operator moves all the bits to the left one position. The numbers are represented in a binary form, therefore it adds a new 0 on the right side:

// 5 in base 2:
101

101 &lt;&lt; 1
→ 1010 (which is 10 in base 2)

Similar things happen when using the >> operator.

84 &gt;&gt; 1
→ 42

From my testing, using this << is about 1.04 times faster than using the * operator. Not sure if you want to sacrifice the human-readable code for such a small speed difference. Maybe. Anyway, it’s good to know.

Send encrypted messages

The XOR (^) operator is used in cryptography. You can encrypt and decrypt messages using it. Here is how it works:

A   B   ^
=========
0   0   0
0   1   1
1   0   1
1   1   0

A simple example would be encrypting and decrypting a number:

// Alice and Bob share the same secret key:
let key = 123;

// Alice wants to send Bob a number
let msg = 42;

// But before sending it, Alice encrypts it:
msg = msg ^ key // or directly: msg ^= key
→ 81

// Bob receives 45, but knowing the key is 123 he knows to decrypt it:
81 ^ key
→ 42

// Now Bob can enjoy the message from Alice

Find if an element is part of an array

Using the bitwise NOT (~) operator we can check easily if an element appears in an array or not.

let fruits = [&quot;apple&quot;, &quot;pear&quot;, &quot;orange&quot;];

// Usually they do it like this
if (fruits.indexOf(&quot;pear&quot;) !== -1) {
   ...
}

// That works, but using the `~` makes the code shorter
if (~fruits.indexOf(&quot;pear&quot;)) {
   ...
}

This operator turns -1 into 0 (because of its internal binary representation, turning 0 into 1 and 1 into 0), while for other numbers it returns non-zero results. Since 0 is a false value (!!0 → false), that’s why it won’t enter in that if condition.

Tip: If you’re using ES2015, includes will do the job:

[&quot;pear&quot;, &quot;apple&quot;].includes(&quot;apple&quot;)
→ true

4. Represent Strings By Using Hex/Unicode Code

If you want, for some weird reason, to hide a string in the code, without calling any functions, you can do that natively. Use wither hexadecimal or unicode escape sequences:

// Hex: '2a' (in base 16) is 42—representing the ASCII code of '*'
'\x2a'
→ '*'

// Unicode: it expects 4 hex digits
'\u002a'
→ '*'

Let’s create a simple function that is supposed to convert human-readable messages:

let strToHex = input =&gt; input.split('').map(
    // Convert each character into its hex code
    c =&gt; `\x${c.charCodeAt(0).toString(16)}`
).join('');

// Let's convert something.
strToHex('hello world!')
→ '\\x68\\x65\\x6c\\x6c\\x6f\\x20\\x77\\x6f\\x72\\x6c\\x64\\x21'

// Once we have the above output, we just have to remove the escaping:
$ echo '\\x68\\x65\\x6c\\x6c\\x6f\\x20\\x77\\x6f\\x72\\x6c\\x64\\x21' | awk 'gsub(&quot;\\\\\\\\&quot;, &quot;\\&quot;)'
→ \x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64\x21

// And finally, we have it!
\x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64\x21
→ 'hello world!'

5. Short-Circuiting Binary Logical Operators

In a binary expression, the second operand is not evaluated if the first one met the result conditions. Let’s take a look at some examples:

true &amp;&amp; 'hello'
→ 'hello'

// We won't get 'hello', because 'false &amp;&amp; anything else' will be always false
false &amp;&amp; 'hello'
→ false

// Let's try a logical or
false || 'hello'
→ 'hello'

// When we have more than two, they are interpreted in the obvious way (from left to right)
0 &amp;&amp; false &amp;&amp; 'hello'
→ 0

42 &amp;&amp; false &amp;&amp; 'hello'
→ false

42 &amp;&amp; true &amp;&amp; 'hello'
→ 'hello'

Now, the nice thing is that same is applied for functions.

// Get some random number
let rand = () =&gt; Math.random() + 1;

// Let's create an object to collect some data
let data = {};

// A function to assign some random numbers to that specific key, only the first time
let add = key =&gt; !data[key] &amp;&amp; (data[key] = rand()) || data[key];

// Assign a random number to 'a'
add('a')
→ 1.0398168717659242

// Reassigning won't work, but we get back the existing value
add('a')
→ 1.0398168717659242

// Do the same for 'b'
add('b')
→ 1.4267915083378722

// And for 'c'
add('c')
→ 1.495289329665785

// Let's see how the data looks like internally:
// Seems we do have a clean key-value map
{ a: 1.0398168717659242,
  b: 1.4267915083378722,
  c: 1.495289329665785 }

Obviously, the magic is in the add function. Let’s expand this:

// Let's see what's going on here
let add = key =&gt; !data[key] &amp;&amp; (data[key] = rand()) || data[key];

// Looks more human-readable, but it's longer :D
add = key =&gt; {

   // If the value is not yet set...
   if (!data[key]) {
      // set it!
      data[key] = rand();
   }

   // Always, do return the value
   return data[key];
};

6. Running Eval in Strict Mode Is Not That Bad

Yes, eval is evil, but maybe it has some features which can help you in your mad-science projects.

When running eval in strict mode, it doesn’t let you create variables in the surrounding scope. Eval simply interprets and executes the code you pass in:

let x = 35;

// Sum x + 7
let result = eval('x + 7');
→ 42

// You can declare variables there (we are NOT in the strict mode):
eval('var y = x + 7');
console.log(y);
→ 42

Now, when we enable the strict mode, the second eval call above will still work, but will not create the y variable outside of the eval environment:

&quot;use strict&quot;;

let x = 35;

eval('var y = x + 7');
//        ^
// ReferenceError: y is not defined
console.log(y);

7. Create Functions Dynamically

We can define dynamic functions using the new Function constructor.

let square = new Function('x', 'return x * x');

// Let's see how it looks like:
console.log(square.toString());
function anonymous(x
/**/) {
return x*x
}

square(4)
→ 16

One use-case when this is used is in templating libraries (such as ejs, ajs etc) which parse the template once and return a function that accepts the template data in it.

Note: You should not use eval or new Function for cases like parsing JSON data, getting the value of a dynamic object key.

Hopefully, you learned something new or at least got a better understanding of what is going on with these JavaScript gems. What other unexplored/uncommon JavaScript features do you know? Share them in the comments.

Ionică Bizău

Programmer, Geek, *nix user, Pianist, Dropout, Learner, Mentor, Vegetarian, Jesus follower, Founder and CEO of Bloggify. Follow me on Twitter.

Posts by Ionică Bizău
🍪

We use cookies to ensure that we give you the best experience on our website. Privacy Statement.

  • I disagree
  • I agree