JavaScript is a programming language that allows you to implement complex features on web pages and, to cut a long story short, you have already known a lot about JS since it is the most popular programming language in 2019 (it’s not our opinion, all figures we got from Developer Survey 2019 from Stackoverflow). If you don’t hear of this survey you should take a look, while we continue our introduction.
Since JavaScript is the basis of any web application, we are not going to discuss JS benefits or a list of JS possibilities. Instead, we will show you some typical mistakes that almost every JavaScript programmer has made during his career.
According to the same Stackoverflow survey, 41% of programmers that took part in the survey have less than five years of professional coding experience.
This article is mostly for those developers. New developers (0-2 years) may find examples from the article useful because it’s a bad code you can learn from. More experienced developers (3+ years) may get a smile by recognizing the JavaScript mistakes you have made in the past. Anyway spending some time reading this article gives you either knowledge or fun. Enjoy reading!
The list of common JavaScript mistakes:
- Do you remember the difference between «=», «==» and «===»?
- Forgetting about the scope of variables.
- Misunderstanding the difference between “let”, “const” and “var”.
- Incorrect references to instance methods.
- Difficulties of using this.
Do you remember the difference between «=», «==» and «===»?
Odds are you first encountered the problem with code like this:
var x = 1;
if (x = 7) {
alert("Hello");
} else {
alert("Nope");
}
And you get “Hello”! Why? The answer is very simple: you don’t understand the difference between the 3 operators mentioned above. It’s not a complicated mistake, and once you learn it you will not likely forget it. Since this mistake is very simple, you can overlook it when it comes to conditions of jumping out of a loop.
Let’s get this thing over with and go further:
“=” is the equal operator, so it’s used for assignment. In our example, we assign seven to “x” in the condition and get words of welcome “Hello”.
The correct code looks like this:
var x = 1;
if (x == 7) {
alert("Hello");
} else {
alert("Nope");
}
We get “Nope”.
“==” is the loose equality comparison operator. Why loose? Because it allows converting values from one type to another to compare them. Even if we assign a string value “7” to x, and compare it with number value “7” the code returns to us “Hello”. However, the code below returns “Nope”:
Why? Because “===” is the strict equality comparison operator. If this operator returns “true” it means that our values are identical both in value and in type. There is an analog for “===” – the method Object.is. It has some differences in the processing of -0, +0, and NaN values, but some of you know what these differences are, while others can turn to JavaScript Guide. And in general, it’s a good practice:
If you have any doubts about JS methods or features, you can always google it, but we highly recommend using JavaScript Guide.
Forgetting about the scope of variables
Another quite simple mistake:
let arr = [1,2,3,4,5,6,7];
var j;
for (j=0; j < arr.length; j++) {
console.log (arr[j]);
}
// …some long code
console.log ( j ); // we get the number “7”
And it’s easy to forget that our variable changes its value after the loop. This mistake exists not only in the JS community but in general. In some languages, you define a variable only within a loop, and it’s destroyed once the loop ends, but not in JavaScript.
And the opposite situation, when you try to get access to a variable that was defined within their local scope (it refers to Function scope). Example:
function myFunction() {
var me = "You can't touch me!";
}
console.log(me);
“me” is not defined, sorry, you can contact your lawyer or just remember the scope of variables in JavaScript. The correct code is:
var me;
function myFunction() {
me = "You can't touch me!";
}
console.log(me + ‘I Can, sorry’);
Another example since JS update in 2015, and the keyword let came to JS to declare variables (ECMA Script 6) is:
let arr = [1,2,3,4,5,6,7];
for (let j = 0; j < arr.length; j++) {
console.log(arr[j]); // the output: 1, 2, 3, 4, 5, 6, 7
}
console.log(j) // j = 0.
The keyword let didn’t change the variable “j” compared to the first example. And this question is the topic of our next abstract
Misunderstanding the difference between “let”, “const” and “var”
It’s closely related to the previous problem, but since almost everybody googled “the difference between var, const and let” we separate this question. Let’s first look at the code below:
console.log(x); // undefined
var x = 5;
console.log(x); // the output is 5
The code is logical as the output, no questions. Another example:
console.log(x); // Error: cannot access “x” before the initialization
let x = 5;
console.log(x);
The reason is that var is function scoped and let is block scoped. When you declare a variable with let keyword, they are moved to the beginning of the block. This may lead to a reference error when you try to access the variable before the initialization.
It’s called a “temporary dead zone”, if you want to know more information about it, you can visit an official website for JS developers Mozilla JavaScript Guide.
But we move on with our next participant and show an example to describe everything:
let a = 5;
var b = 10;
const c = 11;
if (a === 5) {
let a = 4; // The scope is inside the if-block
var b = 1; // The scope is global
const c = 15; // The scope is inside the if-block
console.log(a); // 4,
console.log(b); // 1
console.log(c); // 15
}
console.log(a); // 5, the value changes to the initial
console.log(b); // 1, the value from if-block saves
console.log(c); // 11, the value changes to the initial
And the last code for this chapter:
a = 10; // it’s OK, the value of a is changed to 10
b = 20; // it’s OK, the value of b is changed to 20
c = 7; // SyntaxError: Identifier "c" has already beed declared
const c = 15; // The same error
What happened? In “if block” we declared “a” and “c” variables in if-block and changed the value of a global variable “b”. Outside the block “a” and “C” returned to its initial values. After that, we tried to change the values of all variables: let and var allow us to do that, while const returned an error. The reason is that the const declares a read-only reference to a value within a certain scope (it may be local or global). That’s why we managed to declare the new value of the “C” variable in if-block but failed to change the value outside of it.
Incorrect references to instance methods
Let’s create a new object and use the prototype property of a function to add “whoAmI” method. Then create an instance “obj” of our object (the code below):
var MyObject = function() {}
MyObject.prototype.whoAmI = function() {
console.log(this === window ? "window" : "MyObj");
}
var obj = new MyObject();
The preparatory phase ended, let’s start to make our life simpler: since we need to get access to a recently established method and we want to make it simple, so let’s create a reference to it and check if it works properly.
obj.whoAmI(); // MyObj
var anotherMethod = obj.whoAmI;
anotherMethod(); // window
And we get the output “window” instead of expected “MyObj”.
Why? Well, when we create a reference varanotherMethod = obj.whoAmI, method whoAmI has been defined in the global scope. A global scope is a window object in a browser, so the keyword this becomes equal to the window, not the instance of MyObject. If we want to make a correct reference to an instance method, then we need to call this method from the object itself or make a reference to the object, but not just to the method of the object.
The right reference will look like this:
var obj = new MyObject();
var anotherObj = obj;
anotherObj.whoAmI() // MyObj
or
obj.link = obj.whoAmI
obj.link(); // MyObj
And we get an equal result finally.
Difficulties of using this
JavaScript has become quite a complicated language. This is a keyword in JavaScript the value of which is evaluated during the run-time, depending on the context.
function myFunction() {
var myObject = {
objProperty: "some text",
objMethod: function() {
alert(objProperty);
}
}
myObject.objMethod();
}
myFunction();
And we get ReferenceError: objProperty is not defined. Functions defined on a JavaScript object accessing properties on that JavaScript object and failing to use this reference identifier. The correct code looks like this (not our this =)):
function myFunction() {
var myObject = {
objProperty: "some text",
objMethod: function() {
alert(this.objProperty);
}
}
myObject.objMethod();
}
myFunction();
The idea is simple: when myObject.objMethod is called, this becomes myObject during the call of objMethod. When we define an object and want to access its properties and methods, we need to access the object itself first. (sounds logical) But there are also reverse situations when this is used incorrectly.
Game.prototype.restart = function () {
this.clearLocalStorage();
this.timer = setTimeout(function() {
this.clearBoard();
}, 0);
}
It returns to us another error: undefined is not a function.
The point is that this in this.clearBoard() line is unnecessary here because when you invoke setTimeout() you work with window.setTimeout(), so you invoke the window object in the browser. The object window doesn’t have a clearBoard() method. The correct form will look like this:
Game.prototype.restart = function () {
var self = this;
this.clearLocalStorage();
this.timer = setTimeout(function() {
self.clearBoard(); // this = window
}, 0);
}
And an example that has existed since EcmaScript2015 was released:
Game.prototype.restart = function () {
this.clearLocalStorage();
this.timer = setTimeout(() => {
this.clearBoard(); // this = Game
}, 0);
}
That also became possible after ECMAScript 6. When we use an arrow function, we stay in the scope of the previous function without creating a new local scope.
Memory leaks, what lays beyond it
Let’s start with a code:
function myFunction() {
me = "You can't touch me!";
}
It’s an altered example from the second chapter of this article, can you see the difference?
If yes, it’s great – you are aware of declaring unnecessary global variables and stay careful when it comes to the speed of your code. The problem with this code is that when we call the function myFunction, we create an unnecessary global variable that is lurking in the background until the code doesn’t terminate. The global variable is created because we assign a value to a variable that hasn’t been declared before.
Although the variables don’t take a lot of memory, too much data stored as cash slows the page download speed and negatively affects the speed of your browser in general. There are several possible solutions:
Use local variables:
function myFunction() {
var me = "You can't touch me!";
}
Use “use strict” Directive that doesn’t allow you to invoke undeclared variables:
function myFunction() {
“strict mode”
me = "You can't touch me!"; //me is not defined
}
Memory leaks occur when the app stores unnecessary data that the garbage collector doesn’t clean in its run. Another event that leads to memory leaks is when an app consumes memory for a specific task: once the task is completed, memory is released, but sometimes it is not. So the app keeps the memory for no reason (since the task is done).
Let’s consider another code:
var trigger = document.getElementById("trigger");
var elem = document.getElementById('elementToDelete');
trigger.addEventListener("click", function() {
elem.remove();
});
When we execute the code, elementToDelete is removed from the DOM. But we still have the reference to it within the listener, and at this point, the memory leak happens because allocated memory for the object is still used.
The solution is here:
var trigger = document.getElementById("trigger");
trigger.addEventListener("click", function() {
var elem = document.getElementById('elementToDelete');
elem.remove();
});
Here elem is declared inside the listener. Thus when we delete it, the path for the object is cut off and the memory will be released.