Common mistakes when working with Javascript

Tram Ho

Every developer sometimes makes mistakes when writing applications. This is a basic part of the development process. In particular, there are some errors that will be made more often than others. It would be good to know them and prevent them before they do. Once we do that, we will develop the application a lot easier. Here are 10 common mistakes that JavaScript developers often encounter:

Wrong reference to this

The coding techniques and designs in JavaScript are becoming more and more sophisticated, and with the increase of self-referencing scopes in callbacks and closures, a source of confusion about this / that.

Consider the code below:

Executing the above code will result in an error:

Why?

We need to consider the context . The cause of the above error is because, when you call the function setTimeout() is actually here you call the function window.setTimeout() . As a result, the function you pass into setTimeout() is defined in the context of the window object. this here is a window object and it doesn’t have the clearBoard() function clearBoard()

The traditional solution is to store references to this in a variable and can be used by closures.

In a more modern way, you can use bind() to pass a correct reference:

Think there is block-level scope

One mistake developers make is to assume that Javascript creates a new scope for each code block. Although this is true in many other programming languages, it is not true with Javascript.

For example, consider the following code:

If you thought console.log() would print undefined or throw an error, you’re wrong. Believe it or not, it will print the output as 10. Why?

In most other languages, the above code will fail because the variable i can only be used in the block of the for loop. However, in JavaScript, the variable i is still in scope even after the loop for ending and retain its value after exiting the loop. This behavior is called variable hoisting.

It is worth noting that block scope is supported in Javascript via the let keyword.

Memory leak

Memory leak is an almost unavoidable problem in Javascript if you are not consciously avoiding it. There are many ways that can leak memory, so we will only highlight some common cases.

Example 1: Loose reference to objects no longer exist.

Consider the following code:

If you execute the above code and monitor the memory used, you will see a large amount of memory leak, 1MB per second. That looks like we’re leaking longStr every time replaceThing is called. But why?

Please take a closer look.

Each theThing object contains 1MB longStr object. Every second, when we call replaceThing , it holds a reference to theThing object first in priorThing . But perhaps this is not a problem, because every run through, previous references to priorThing will be canceled (when priorThing is reassigned via priorThing = theThing; ). Moreover, it is only referenced in the body of the replaceThing function and in the unused function is never used.

So why is there a memory leak here?

To understand what happens, we need a better understanding of how things work in Javascript. If both functions defined in replaceThing actually use priorThing , then it is important that both receive the same object, even if priorThing is reassigned, both functions still use the same lexical environment. But as soon as a variable is used by any closure, it ends in the lexical environment shared by all closures within that scope. And it leads to memory leak.

Example 2: Circle reference

Here, onClick has a closure that holds the reference to the element (via element.nodeName ). By assigning onClick to element.click , a circular reference is created: element -> onClick -> element -> onClick -> element

Even if the element is removed from the DOM, the above reference will still prevent the element and onClick being cleaned, and thus, lead to memory leaks.

Preventing memory leaks: What you need to know

Memory management in Javascript depends mainly on object access.

The following objects are said to be accessible and are considered to be root:

  • Objects are referenced from anywhere in the current call stack (all local variables, parameters in the function being called, variables in the closure scope)
  • All global variables.

Objects are kept in memory at least as long as they are accessible from any root via a reference or a series of references.

Confused when compared by

One of the advantages of Javascript is to automatically cast a boolean value when referring to a boolean context. But sometimes this convenience is confusing. For example, some of the following are often annoying to Javascipt developers:

As the example described above, cast rules are sometimes unclear, so it’s better to use === instead of == .

One more thing to note is that comparing everything with NaN will always return false . Therefore, to determine a value of NaN to use an available global function isNaN() :

DOM manipulation is not effective

Javascript provides the ability to manipulate DOM elements quite easily, but there is no incentive to do so effectively.

A common example is adding a series of DOM elements at once. Adding a DOM element is a costly operation, so the simultaneous addition of DOM elements is inefficient and may not work properly.

An effective alternative when more DOM elements are needed is to use document fragments . It will improve both efficiency and performance.

For example:

Using the wrong function definition in the for loop

Track the following code:

In the above code, if we have 10 input elements, when clicking on any element, we will get the message “This is element # 10”. This is because when the onclick is triggered on any element, the for loop is then completed and the value of i is 10. The following is how to fix the above code to achieve the desired behavior:

With the above fix, makeHandler is executed immediately each time through the loop, taking the parameter i + 1 and binding it to the scope of the variable num . This will ensure that each onclick event will get the appropriate i value through this num variable.

Do not thoroughly apply the prototype inheritance

A large number of Javascript developers do not fully understand and take full advantage of the features of prototype inheritance.

For example:

It looks pretty simple. If passed in the name , it will be used, otherwise the name will be assigned as “default”.

But if we do the following:

then you will get:

But it would be better if it was the “default” default value. This can be achieved by leveraging prototype inheritance:

In this way, BaseObject inherits the name attribute from the prototype object. If the name attribute is removed from an instance of BaseObject , the prototype chain will be searched and the name will be taken from the prototype object and set to “default”. So we will have:

Create incorrect references to instance methods

Let’s define an object, and create an instance of it:

Now, for convenience, make a reference to whoAmI and we can call it by whoAmI() instead of obj.whoAmI() .

To make sure everything matches, print out the value of whoAmI :

Result:

Ok, looks good.

But now, look at the difference when we call obj.whoAmI() and whoAmI() :

What is wrong here.

When we perform the assignment var whoAmI = obj.whoAmI; , whoAmI variable is defined in global namespace. As a result, the value of this is window , not the object instance of MyObject .

Therefore, if we need to make a reference to a method of an object, we need to make sure that it is done in the namspace object to hold the value of this . For example:

Use string as the first parameter of setTimeout or setInterval

Passing the first parameter to setTimeout or setInterval a string value is not an error. The problem here is about performance. If we pass such a string parameter, it will be sent to the constructor function and converted into a new function. The process is slow and inefficient, and really it’s not necessary.

Instead of writing the following:

Please convert it into:

Do not use “strict mode”

“strict mode” is a way to enforce parsing and error handling more strictly with Javascript code at runtime.

Here are some key benefits of using “strict mode”:

  • Making debugging easier: bugs that can be ignored or fail silently will be thrown exceptions.
  • Prevent from accidentally creating global variables: If “strict mode” is not used, assigning values ​​to an undefined variable will automatically create a global variable. This is a fairly common mistake in Javascript. With “strict mode”, doing so will throw an exception.
  • Prevent reference to this as null or undefined.
  • Duplicate names of attributes of an object or parameters of a function are not allowed.
  • Throw error when using wrong delete . delete cannot be used with non-configurable properties. When not using “strict mode”, such behavior will fail quietly without our knowledge. But with “strict mode” the error will be reported.

Refer

https://www.toptal.com/javascript/10-most-common-javascript-mistakes

Share the news now

Source : Viblo