Let’s dive into some common JavaScript pitfalls—those frustrating moments when something doesn’t work as expected, and we need to figure out why.
JavaScript has come a long way since its creation. Over the years, many new features have been added to the language, and some are now preferred over older approaches to help avoid common mistakes. Sometimes, though, it’s not about the features but simply that a developer hasn’t yet encountered or understood why something behaves the way it does.
So, let’s get into some examples and solve these issues together!
The for in problem
Looping using the for in
loop is different compare to the for of
loop, and it is common to mix those.
Let’s say we want to loop over an array of names and print them to the console, can we spot the problem here using the for in
loop?
If you guessed that it will print out the names it’s wrong!
We are getting 0,1,2
printed to the console.
The question is why?
We need to understand how the for in
loop works.
The for in
loop to not loop over the values but instead loop through the keys in an object. Since arrays in javaScript are plain object we bailly get the indexes and not the values.
To solve the problem we could just change to using the for of
loop instead.
Now we get the expected result: Alice, Bob, Eve
.
Overusing Optional Chaining
Optional chaining is an excellent feature that has made our code cleaner and more readable compared to the old approach of using if statements to check if properties exist on an object.
However, I believe it’s sometimes used incorrectly. Not all checks or potential errors should be silent. There are cases where it’s better to explicitly handle errors or indicate when something is missing.
Let’s look at an example:
Suppose we want to iterate through our users’ data and retrieve their themes saved as user settings.
Using optional chaining, we would get [dark, undefined, undefined].
Instead, let’s check if user.profile.preferences actually exists before adding it to the list. If it doesn’t exist, we should at least log an error so developers are aware of the issue.
Immutable objects
A common misconception among JavaScript developers is regarding immutability in the language. While it’s important to differentiate between var
, let
, and const
—which is a separate topic—it's crucial to remember that const
does not make values immutable; it simply prevents reassignment of the variable.
Here, I'd like to focus on how Object.freeze()
operates. This useful API allows us to create immutable values in JavaScript.
However, it's important to note that Object.freeze()
only applies to objects that are one level deep. When you begin to add nested objects, Object.freeze()
does not ensure the immutability of those inner objects.
The id
property on the data
object cannot be mutated as expected.
What occurs if we attempt to change the name
property within the user
object instead?
As you can see, we have successfully mutated the user's name.
Be cautious and aware of these types of issues when using Object.freeze()
in your programs.
This keyword in arrow functions
I believe the arrow function in JavaScript is often overused. While choosing between the function keyword and the () =>
syntax often comes down to design principles and personal preference, it’s crucial to understand the key differences and potential pitfalls.
In this example, I’ll demonstrate a scenario where using an arrow function would lead to unexpected results, and show how switching to the function keyword resolves the issue.
We get undefined
when trying to access the name. Why does this happen?
The issue lies in the greet
method, which incorrectly uses the this keyword within an arrow function. Arrow functions don’t have their own this context; instead, they inherit this from the surrounding lexical scope. In this case, this does not refer to the user object as intended.
To fix this, we should use a regular function for the greet method instead of an arrow function.
Now, greet
is a regular function, and it correctly refers to the user object using this.
Conclusion
JavaScript is a versatile and powerful language, but it’s easy to make mistakes if you’re not aware of the language’s nuances and best practices. By understanding these common pitfalls and how to avoid them, you can write cleaner, more efficient code and become a more proficient JavaScript developer.