Unravelling JavaScript: Commonly Misunderstood Methods and Features

Abstract image used to represent Commonly Misunderstood Methods and Features of JS
Image by Lysander Yuen.

Sort [2, 10] without a comparator and JavaScript puts 10 first. Swap slice() for splice() and a harmlesslooking array operation starts changing the original data. Small differences in familiar methods can produce surprisingly awkward bugs.

This is a starting point for a series of closer looks at those differences. I'll use each article to explain the behaviour, show an example, and point out what I would check when the method appears in a code review.

Here are the methods and features I want to look at:


Array.prototype.sort()

There's more than meets the eye with sort(). Have you ever tried to sort an array of numbers and ended up with 10 before 2? That's sort() in action, treating elements like strings.

Elsewhere, I go into more detail on understanding Array.prototype.sort() here, and into even deeper detail on how you can use sort() to sort arrays of objects (like sorting products by prices) here.


Array.prototype.slice()

Using slice() silently duplicates sections of your array without altering the original. It is really common to see this mistaken with its more invasive counterpart, splice(), which behaves quite, quite differently...

I talk about using slice() in detail here.


Array.prototype.splice()

splice() is a bit of a multitool for arrays, capable of adding, removing, and replacing elements. Its versatility can be daunting and easily misunderstood, making it prone to misuse.

Read more about manipulating arrays with splice() here. I go into even more detail comparing slice() against splice() in my article here.


String.prototype.substring()

Extracting parts of a string should be simple, and substring() is just the tool for the job. It extracts characters from a string (just as you'd expect), but unlike its relative slice(), it has some confusing peculiarities when it comes to dealing with negative or outoforder arguments.


String.prototype.substr()

substr() is a legacy method specified in Annex B of ECMAScript for web compatibility. It is optional outside browsers, so I would choose substring() or slice() for new code. When reading an existing call, remember that substr() takes a length as its second argument; substring() takes an end index. Their treatment of negative arguments differs too.

I talk about substring() and substr(), comparing the two in my article here.


String.prototype.split()

split() should be simple: give it a string and should return that same string in an array, broken down based on a predefined delimiter. However, understanding how different delimiters, or their absence, affect the output makes it more complicated than you might expect.

I've written an article all about manipulating string with split() here.


Math.random()

I've written about Math.random() before, and how actually you cannot create a truly random value using maths. Nevertheless, Math.random() is a pseudorandom number generator that can mislead those expecting numbers outside of the 0to1 range.


parseInt()

Turning strings into integers with parseInt() can lead to some unusual and unexpected results if you ignore the radix. How it behaves with unexpected characters in the string can also result in hardtofind bugs.

I've written about parseInt and the importance of understanding radix here.


isNaN()

The isNaN() function checks if a value is NaN ("Not a Number"), but it can return true for unexpected inputs, making it unreliable without understanding its coercion rules. I go into this in much more detail in a previous article here.


typeof

It may seem like typeof is a straightforward gatekeeper for type checking but can often output types that aren't accurate, particularly when it comes to arrays and null.

I have written about typeof, how it can be used and where it becomes more limited here.


instanceof

instanceof checks the prototype chain for a constructor but can quickly lead to false negatives, especially when dealing with multiple contexts, such as different iframes or realms.

You can read about instanceof and its uses in detail in my article here.


null and undefined

Both null and undefined represent "no value", but they have different meanings and uses. They are not interchangeable, especially in comparisons.

This is something I've written about before.


== and ===

The equality (==) and strict equality (===) operators are similar at a glance, but understanding their coercion rules is vital to prevent unexpected type conversions. I've written about the differences between these equality operators and their uses before.


Object.prototype.hasOwnProperty()

hasOwnProperty() checks for a property's existence directly on an object, not on its prototype chain. This distinction is easy to overlook and can lead to incorrect assumptions about an object's properties.

Read a brief overview of hasOwnProperty in my article here.


Function.prototype.apply()

apply() calls a function with a given this and arguments provided as an array. It can be intricate to master, especially when dealing with the arguments arraylike object.

I go into detail about .apply() in my article here.


Function.prototype.bind()

bind() returns a new function with a preset this value and optional initial arguments; it does not call the original function immediately. apply() and call() invoke the function straight away. That timing difference matters when passing a callback for another part of the application to run later.

You can read about .bind() in my article here.


setTimeout()

Any JavaScript developer should know, setTimeout() schedules code to run after a defined delay. However, its timing can be imprecise due to JavaScript's singlethreaded nature and event loop.

I have written about using setTimeout and the potential issues with timing accuracy here.


setInterval()

On a similar vein to setTimeout(), setInterval() is a handy way to run code at regular intervals, however, it can quickly result in queued calls if its callbacks take longer than the interval time.

Read more about setInterval in my article here.


Object.defineProperty()

defineProperty() configures properties with fine granularity, including descriptors like writable and enumerable. However, the complexity of these attributes often leads to misuse.

I talk about harnessing this powerful JavaScript method here.


Promise.prototype.then()

The then() method is the backbone of promise chaining, yet it is often misunderstood because it is used to handle the success or failure of a promise, whilst it returns a new promise that can itself be chained to other promises. It can get very confusing.

I have written about leveraging then() in modern JavaScript here.


Want to find out more?

If you need senior handson support with a complex React or Next.js platform, migration, performance issue, or technical SEO problem, send me the context and I'll tell you where I can help.