(Im)possible errors in JavaScript

(Im)possible errors in JavaScript

Introduction

javascript error

JavaScript is a specific programming language, and compared to other languages, it sometimes solves problems in a different way than expected, but that doesn’t mean that way is wrong. Behind every “weird” decision regarding language syntax is a good reason why the JavaScript development team chose it. In order to understand the specifics of the language, it is necessary to thoroughly study the syntax and principles of the language. There are a small number of illogicalities that I still can’t “digest” so easily, but nobody is perfect and neither is JavaScript. It is considered that programmers who come into contact with JavaScript as a second language have a little more trouble to adapt, because they expect the same principles as in their favorite programming language but do not find them here either. In this article, I’ve collected potential (un)forced errors that a mere JavaScript mortal can make. The article will be updated regularly as I make mistakes 🙂

Strange results when adding decimal numbers

This problem occurs because in some cases decimal numbers cannot be represented as a binary fraction (eg 1/3 cannot be represented as a decimal fraction). This behavior can be a problem in expressions such as:

Solution

If certain accuracy is required, the following procedure can be used:

Or

Implicit type change

Implicit (hidden) type conversion refers to conversions that are not obvious, and are performed by the JavaScript engine on the fly as a side effect of some other actions. Implicit conversion most often occurs when a value of a type is used in a way that automatically causes its conversion.

Associability of operations and conversion of logical value to number

From a mathematical point of view, the following snippet is incorrect in all respects, but if you know that the less sign “<" in JavaScript, the comparison operator with its set of rules becomes clear why the result is TRUE:

Explanation:

The associativity of the “<" operator is from left to right, so the expression after grouping looks like this:

Solving the first operation results in the logical value FALSE, so the expression looks like

When comparing two elements of different types, there is an implicit conversion of FALSE to the number “0”, after which the expression looks like:

See more about operators in the article “JavaScript operators”

Implicit conversion to boolean type when comparing

In the case when operands that are not of logical type are compared with logical operators (&& or ||), due to the examination of the conditions of the operator, there is an implicit conversion of operands into logical type. However, the operators && or || after solving the condition do not return a logical value, but return the value of one of the two operands. The result of the condition is determined according to the followingrules:

  • For the operator || after the conversion of the “not logical” type to logical when resolving the condition, the rule applies that if the result of the operator’s condition is:
    • TRUE returns the value of the first operand
    • FALSE returns the value of the second operand
  • For the operator && after the conversion of the “not logical” type to logical when resolving the condition, the rule applies that if the result of the operator’s condition is:
    • FALSE returns the value of the first operand.
    • TRUE returns the value of the second operand

Explanation of example results:

Respecting the precedence of the operators used, the logical “and” takes precedence over the logical “or”, so the previous expression can be converted to:

To determine the conditions in the parentheses, the implicit conversion of the types into the logical type is first performed temporarily, after which the calculation with the operand && is performed on the obtained logical types:

The solution to the condition (TRUE && TRUE) is TRUE, so according to the rule if the result is && TRUE the operator returns the value of the second operand (in this case “foo”), so the sorted expression looks like this:

In order to determine the conditions, the implicit conversion of the types into the logical type is first performed temporarily, after which the calculation with the operand || is performed on the obtained logical types:

The solution to this condition is TRUE, after which the || operator returns the value of the first operand (which is “foo”) according to the rule.

See more about operators in the article “JavaScript operators”

Implicit conversion of Object to string

If we want to print an object in the console along with the accompanying text, we get an unexpected result:

Using the + operator with non-number operands is not addition but string concatenation. Concatenation is a privilege of stings, therefore the result from the previous example is a consequence of the implicit (hidden) conversion of the object into a string.

From the above it follows that any conversion of object to string returns “[object Object]”

Solution:

In order for the object to be “nicely” printed, we must first transfer the JavaScript object to a string with the JSON.stringify() method:

NOTE:
If we put a comma instead of + on the first snippet, we will get the desired result, because the comma operator performs the set task for all comma-separated parameters and does not cast the object into a string:

Implicit conversion of string to string

When concatenation results in an implicit conversion of an array to a string, they get slightly different results:

Read more about this in the article Type conversion in JavaScript”

Strict object comparison?

Comparing objects with the “===” operator always returns FALSE because objects are passed by reference in memory. The following example strictly compares two objects with the same values, but since those values are stored in two different places in memory, the comparison is always FALSE:

When assigning an object to a variable, a reference to the place where the object is stored in memory is passed. Objects (including arrays) are stored in a type of memory called a “heap”.

However, you should know that the following code returns TRUE, because both point to the same place in memory:

For more about data with reference values, see the article “Data Types in JavaScript”

Type of Null!?

One of the odd and strange things about the syntax of the language is the fact that null is of type object!!!

Controlling the existence of an object is a problematic task, because the conditional condition obj !== “undefined” gives false positive results for null:

For the previous reason, the typeof method is most often used, which returns a string that defines the data type.

However, the previous check is not sufficient because the object may have a null value assigned to it:

But even the previous code is not good enough because if the object is undefined then it is not null, so it is better to first ask if it is different from undefined:

Built-in objects that look like primitives

In JavaScript, in addition to the “object” type, there are 6 other “simple primary” types that are not objects: string, number, boolean, undefined, null and symbol. But confusion is often caused by the fact that in addition to primitive types there are built-in objects whose names are the same as those of simple primitives as long as the names start with a capital letter: String, Number, Boolean, Function, Array.

Often there is an implicit conversion of a simple primary type to its “counterpart” object, which leads to unexpected results in a strict comparison. The following example shows that a strict comparison returns false:

In the previous example, snippets return FALSE, because using the reserved word new creates a new object.

Read more about this in the article “Data types in JavaScript” under the section “Is everything in JavaScript an object?”

Strict comparison within Switch() statement

The previous snippet will never trigger an alert, because the switch statement requires matching the data type. But if we first cast the variable into a string, the next snippet will give correct results.

Specificity of the replace() method

It is necessary to know that the method replace() affects only the first element it finds:

Thereforeif we want to apply string replacement to all required elements, we need to use regular expression globally:

Month numbering problem in Date object

Months in JS object “date” start numbering from zero, unlike year and day which start numbering from number one.

Defining an array with one argument

If you put only one value when declaring an array, JS considers it to be the “length” of the array. This is why JavaScript creates an array of such length whose members are not yet defined.

The problem of sorting a sequence of numbers with the sort() method

The sort() method is initially intended to sort an array of strings, therefore it gives wrong results when sorting an array of numbers. For use with numbers, you need to add a comparison function.

Solution

For use with numbers, you need to add a comparison function.

Function arguments

Length functions

The length property of functions returns the number of defined arguments (here there are 2: a,b) in the function (not passed or used arguments).

Specificity of the “arguments” object

Arguments is an “Array like” object, therefore, unlike a “normal” object, it has a length property. The delete operator is used to delete object properties, in the following example we want to delete the first property of the arguments object.

However, even though the operator deleted the first property of the “arguments” object, it does not affect the value returned by the length() method, because the length method returns the number of arguments passed to the function (in this case there are 3 pieces: 5, 7, 9).

Shading variable (shadowing)

The fact that the variable from the outer scope is always available to the code inside the inner scope can “trick” us into thinking that “initial is 1000” will be printed. However, variable shadowing occurs here. When the JavaScript engine searches for the value of a variable, it first looks in the nearest area of ​​definition, and since the variable is defined within the function, it finds it there (it still does not search, so it never reaches the external variable). In addition to “shadowing the variable”, there is also a process of hoisting the variable inside the function. This solution is easily explained in the following snippet, where the code is shown at the moment of JavaScript parsing.

The value of “this” in the object’s “underlined” method

A method is just a property of an object that has a reference to some function. When we assign an object method to a variable, we have assigned a function reference to the variable. Therefore, by calling that variable, we are not calling a method of the object but an ordinary function from the global domain. The keyword THIS inside a function that is called from the global scope according to the rules for THIS points to a global object (window).

Example

Explanation of example

Since the person.fullName method has a reference to an anonymous function, we can insert it in its place, so the previous example from the this point of view goes into the following code:

From the attachment it can be seen that the function displayFullName() is called, not the method of the object. Therefore, the “default rule” is used when this points to a global window object that has no window.name and window.surname properties and returns undefined, undefined.

Problem solution

This problem is solved with the bind() method, with which we will explicitly bind this from the function to the “person” object, after which it no longer matters from where the function is called.

Read more about this in the article “This in JavaScript”

The problem of the callback function in the loop

The unexpected behavior of the callback function in the loop can be attributed to the fact that it is not called immediately while the loop is spinning, but is always called with a “delay” when the loop has already spun and reached the last value of the counter. For this reason the callback function will always use the last value of the counter.

Loop and callback function in the setTimeout() method

Process description

Calling the setTimeout method while the loop is running
After the loop starts, the initial value of the variable “i=0”, after which the setTimeout() function is called. The setTimeout() function will only call the callback function after 10s. While waiting for the callback function to be called, the loop continues to “spin” and now it is “i=1”, immediately after that the setTimeout() function is called, which will call the callback function again in 10s, and while waiting for its execution, the loop continues to spin and now it is “i=2”. The process is repeated until “i” gets a value of 5. This entire previously mentioned process is performed for a very short period of time (measured in milliseconds).
Calling the callback function at the end of the loop
After the first 10sec, the loop has already “twisted” the variable “i” and the first callback function is invoked, which therefore takes the value of the variable “i”, which is 5. The next callback function for is activated for an additional 10sec, and uses the same variable, so the result is the same…

Problem solution:

We can solve this problem if we call the callback function at each loop, so that it “grabs” the value of the variable “i” at that moment. In this way, we create for each pass through the loop a new function, which, thanks to the closure characteristics, is able to “remember” the assigned value of the variable “i” in that loop.

And way:

In this example, we call the function at each round of the loop with the help of IIFE, thus providing it with unique values for each loop.

II way:

This method uses the ES6 property of the let keyword which defines a new variable “i” in each iteration of the loop:

III way:

In this example, we separate the callback function so that in the syntax of the setTimeout() function, we can invoke it every time the loop passes. The Closure will remember that value at the time of invocation and will not be affected by a later change in the value of the variable ie. “redeclaring a variable”

Loop and callback function at addEventListener()

The following example shows a similar problem as with the loop and the setTimeout() function:

See the Pen VWPNPq by Web programming (@chos) on CodePen.

As in any standard loop, an eventListener is added to each element and the loop ends. The moment a button is clicked, the loop is already “twisted” and whichever button is selected, the alert will be the same.

Solution

One possible solution is to put the entire code in an IIFE that will be called at each round and the closure will remember the passed value:

See the Pen gRgyOy by Web programming (@chos) on CodePen.

You can read more about this in the article “Javascript Closure” under the section “Troubleshooting with “this” in the callback function in a loop”