Introduction

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
|
1 2 3 4 5 6 7 8 9 |
// Some values are ok: 0.2 + 0.3 = 0.5 0.2 + 0.5 = 0.7 0.1 + 0.4 = 0.5 // But these values are strange: 0.1 + 0.2 = 0.300000004 0.2 + 0.4 = 0.6000000000000001 0.1 + 0.7 = 0.7999999999999999 |
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:
|
1 2 3 |
if (result == expectedResult) { // Do something } |
Solution
If certain accuracy is required, the following procedure can be used:
|
1 2 3 4 |
var precision = 0.00001; if (abs(result - expectedResult) < precision){ // some code } |
Or
|
1 2 3 4 |
var result = 0.2 + 0.1; if (result.toFixed(4) == expectedResult){ // some code } |
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:
|
1 |
3 < 2 < 1 // ReturnsTRUE |
Explanation:
The associativity of the “<" operator is from left to right, so the expression after grouping looks like this:
|
1 |
(3 < 2) < 1 |
Solving the first operation results in the logical value FALSE, so the expression looks like
|
1 |
FALSE < 1 |
When comparing two elements of different types, there is an implicit conversion of FALSE to the number “0”, after which the expression looks like:
|
1 |
0 < 1 // Returns: TRUE |
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
|
1 2 3 4 5 |
var a = 42; var b = "foo"; var c = [1,2,3]; a && b || c // Rezultat je : "foo" |
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:
|
1 |
(a && b) || c |
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:
|
1 |
(TRUE && TRUE) || c |
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:
|
1 |
"foo" || [1,2,3] |
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:
|
1 |
TRUE || TRUE |
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:
|
1 2 |
var obj = {a:1, b:2}; console.log('The facility is:' + obj); // Returns: "The object is: [object Object]" |
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.
|
1 2 3 4 5 |
var obj1 = {a : 1}; console.log(obj1.toString()); // Returns: "[object Object]" var obj2 = {}; console.log(obj2.toString()); // Returns: "[object Object]" |
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:
|
1 2 3 |
var obj = {a:1, b:2}; var objString = JSON.stringify(obj); console.log('The facility is:' + objString); // Returns: "The object is: {"a":1,"b":2}" |
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:
|
1 2 3 |
var obj = {a:1, b:2}; console.log(obj); console.log('The facility is:' , obj); // Returns: Object is : Object {a: 1, b: 2} |
Implicit conversion of string to string
When concatenation results in an implicit conversion of an array to a string, they get slightly different results:
|
1 2 3 4 5 6 7 8 9 |
var niz1 = [1, 2, 3]; console.log("The array contains:"+ niz1); // Returns "Array contains: 1,2,3" console.log(niz1.toString()); // Returns: "1,2,3" var niz2 = []; console.log(niz2.toString()); // Returns: "" var niz3 = [1, {a:2}, 3]; console.log(niz3.toString()); // Returns: "1,[object Object],3" |
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:
|
1 2 3 |
{[1,2,3] === [1,2,3] // false {a: 1} === {a: 1} // false {} === {} // 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”.
|
1 2 3 4 5 |
var c = {a:1}; var d = c; // ukoliko promeimo value "c" c = {a :2}; console.log(d); // Returns: {a:2} does it point to the same place in memory. |
However, you should know that the following code returns TRUE, because both point to the same place in memory:
|
1 2 3 |
var e = {a: 1}; var f = e; e === f; // Returns: TRUE |
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!!!
|
1 |
typeof null ==="object" // TRUE |
Controlling the existence of an object is a problematic task, because the conditional condition obj !== “undefined” gives false positive results for null:
|
1 2 3 |
if (obj !== "undefined"){ alert ("The object exists") } |
For the previous reason, the typeof method is most often used, which returns a string that defines the data type.
|
1 2 3 |
if (typeof obj !== "undefined"){ alert ("The object exists") } |
However, the previous check is not sufficient because the object may have a null value assigned to it:
|
1 2 3 |
if (obj !== null && typeof obj !== "undefined"){ alert ("The object exists") } |
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:
|
1 2 3 |
if (typeof obj !== "undefined" && obj !== null){ alert ("The object exists") } |
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:
|
1 2 3 4 5 6 7 8 |
(function(n) { return n === new Number(n); })(10); // Returns: FALSE because number and object are compared. ili (function(x) { return new String(x) === x; })('a'); // Returns: FALSE because string and object are compared |
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
|
1 2 3 4 5 |
var myVar = 5; switch(myVar){ case '5': alert("hi"); // It will never activate } |
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.
|
1 2 3 4 5 |
var myVar = 5; switch(myVar.toString()){ case '5': alert("hi"); } |
Specificity of the replace() method
It is necessary to know that the method replace() affects only the first element it finds:
|
1 2 3 |
var a = "bob ili bob"; var rec = "bob"; alert(a.replace(rec, "lol")); // Returns" lol or bob |
Thereforeif we want to apply string replacement to all required elements, we need to use regular expression globally:
|
1 2 3 |
var a = "bob ili bob"; var patern = /b/ig; alert(a.replace(patern, "l")); // Returns: lol ili lol |
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.
|
1 2 |
new Date (2016, 05, 20); // Returns20-ti jun 2016 new Date (2016, 05, 31); // Returns01. jul 2016 (jer jun ima 30 dana pa se prelije u jul) |
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.
|
1 2 |
new Array(3); // Returnsniz [undefined, undefined, undefined] new Array(1, 2, Array(3)); // Returnsniz [1, 2, [undefined, undefined, undefined]] |
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.
|
1 2 |
// Sorting numbers like strings gives the wrong result: [10,1, 5].sort() // [1, 10, 5] |
Solution
For use with numbers, you need to add a comparison function.
|
1 2 3 4 5 |
// Sortiranje brojeva sa ES5 someArray = someArray.sort(function (a, b) { return a - b; }); // Sortiranje brojeva sa ES2015 someArray = someArray.sort((a, b) => a - b); |
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).
|
1 |
(function someFunction(a,b){}).lenght // Returns2 |
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.
|
1 2 3 4 5 6 |
var result = (function(a, b, c) { delete arguments[0]; return arguments.length; })(5,7,9); console.log(result); // 3 |
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)
|
1 2 3 4 5 6 |
var plata = "1000"; (function () { console.log("The starting salary is" + plata); var plata = "5000"; console.log("Nova plata je " + plata); })(); // Returns: "Starting salary is undefined" and "New salary is 5000" |
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.
|
1 2 3 4 5 6 7 |
var plata = "1000"; (function () { var plata; // undefined; console.log("The starting salary is" + plata); plata = "5000"; console.log("Nova plata je " + plata); })(); |
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
|
1 2 3 4 5 6 7 8 9 10 11 |
var person = { firstName:"Pera", lastName: "Peric", fullName: function () { return this.firstName + " " + this.lastName; } } person.fullName(); // Returns: Pera Perić var prikazPunogImena = person.fullName // we assign the variable a reference to the function prikazPunogImena(); // Returns: undefined undefined |
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:
|
1 2 3 4 |
var prikazPunogImena = function () { return this.firstName + " " + this.lastName; } prikazPunogImena(); |
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.
|
1 2 3 4 5 6 7 8 9 |
var person = { firstName:"Pera", lastName: "Peric", fullName: function () { return this.firstName + " " + this.lastName; } } var prikazPunogImena = person.fullName.bind(person) // now we bound this to the "person" object prikazPunogImena(); // Pera Peric |
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
|
1 2 3 4 5 |
for (var i = 0; i < 5; i++){ setTimeout(function(){ console.log(i); }, 1000); } // Returns: 5 5 5 5 5 |
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.
|
1 2 3 4 5 6 7 |
for (var i = 0; i < 5; i++){ (function(i){ setTimeout(function(){ console.log(i); }, 1000); })(i); } // Returns: 0 1 2 3 4 |
II way:
This method uses the ES6 property of the let keyword which defines a new variable “i” in each iteration of the loop:
|
1 2 3 4 5 |
for (let i = 0; i < 5; i++){ setTimeout(function(){ console.log(i); }, 1000); } // Returns: 0 1 2 3 4 |
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”
|
1 2 3 4 5 6 7 8 9 |
function someFunction (i){ return function(){ console.log(i); }; }; for (var i = 0; i < 5; i++){ setTimeout(someFunction(i), 10000); } |
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”

