Best practices in Javascript variable declaration

Asked

Viewed 403 times

7

In the MDN Variables section we have the following statement:

For that Reason, it is Recommended to Always declare variables at the top of their Scope (the top of global code and the top of Function code) so it’s clear which variables are Function scoped (local) and which are resolved on the Scope chain.

This excerpt says that it is recommended to always declare variables at the top of its scope due to the fact that Javascript has the behavior of variable Hoisting.

What are the implications of not following this recommendation? Particularly, I find a code much easier to read when the declaration of its variable is performed at the exact moment before its first use, compared to declaring all variables at the beginning of the execution of a function, for example.

Exemplifying:

// Declarando variável no topo de seu escopo
function(){
    var a = 0, b = 0;
    //some code
    a = 5;
    //some code
    b = 10;
}
//Declarando variável próximo de sua utilização
function(){
    //some code
    var a = 0;
    a = 5;
    //some code
    var b = 0;
    b = 10;
}
  • In comparison to what?

  • 3

    I believe that this recommendation is due to standard reading and maintenance of the code. Imagine a script with 200 lines, where a variable is used on the 180 line and whoever is updating needs to change the initialization of the variable from array to object. In that case you’ll have to hunt down the statement.

  • @bigown updated question

  • 1

    @Lucascosta if the function has 200 lines, the problem is another.

  • Even if the function has 200 lines, if it creates 10 variables, it is no longer difficult to read and maintain its variables with all of them initialized in the first line of the function?

  • 2

    @bigown with scope understood global scope. In fact, a function with 200 lines the problem is another :)

  • @Lucascosta is that global scope ends up being problem tb. And then I agree that if you go this way, declare before is useful.

Show 2 more comments

3 answers

7


If you are aware of how the Hoisting works, the biggest implications are for other people who might be messing with your code.

I believe that this recommendation is based mainly on the consequences of variables captured by closures. For example:

var fns = [];

for(var i=0; i<5; i++) {
  // cria closures
  fns.push(function() {
    console.log('closure sobre i com valor ', i)
  });

}

for(var j=0; j<fns.length; j++) {
  fns[j]();
}

The above code will always log in 5 as the value of i in the console, because there is only one variable i, and 5 is the value of it after the loop. This confuses a lot of people, there are numerous questions about it here on the site. A part of this confusion is because people expect the variable declared in the initializer of the for has restricted scope to the block of for, when in fact it is in the outer scope.

Compare to ES-2015 version using let to declare variables with block scope:

var fns = [];

for(let i=0; i<5; i++) {
    // cria closures
    fns.push(function() {
        console.log('closure sobre i com valor ', i)
    });

}

for(var j=0; j<fns.length; j++) {
    fns[j]();
}

Jsfiddle

In this version, each call logs a different value, which was the value of i at the time of the creation of each closure. This indicates that with let every iteration of for there was a variable i distinct (versus a single i with var). Therefore has the expected behavior of those who are accustomed to block scope.

In fact, in ES-2015 it is recommended to put the statements with let always just before use, precisely because it does not create the same confusion as the var.

6

Problems of Hoisting

In fact you run the risk of Hoisting if you don’t organize the code well. If the pain function is so complicated maybe the problem is something else. Note that if you organize the code right there is no problem at all. It is only the risk of falling into a problematic situation unintentionally. If you have any tool that helps analyze code can prevent some slip-up from happening unintentionally.

I won’t go into detail because the link above already explains better how is the effect Hoisting, but in summary, the variable, superficially speaking, is created at the beginning of the execution of the function, so to declare it there is to make sure that the code expresses the reality of what will be executed. If you declare elsewhere, it may not happen what you expect. Example of a problem:

var x = 0;
function hoisting() {
    console.log(x);
    var x = 1;
    console.log(x);
}
function nonHoisting() {
    var x = 1;
    console.log(x);
}
function nonHoisting2() {
    console.log(x);
}
hoisting();
nonHoisting();
nonHoisting2();

Global scope

I don’t recommend using global scope, but if you do, I think it’s best to declare everything first. The mess is already made, so it’s best to organize as best you can, it’s very easy to slip up in this case. You have placed a function that uses this variable before it has been declared and may already have surprises.

let

This only occurs with the var. With the let this risk does not run. So I find it more interesting whenever possible (whether it will use new version of JS or whether it will pass for a translator. It was created to solve a problem that language had.

So you can do what is actually the most recommended in most cases, which is to declare the variable near where it will be used.. With var, or takes great care or may have the Hoisting.

function teste(){
    //some code
    let a = 0;
    a = 5;
    //some code
    let b = 0;
    b = 10;
  console.log(a + b);
}
teste();

I put in the Github for future reference.

4

What are the implications of not following this recommendation?: This is about clarity and code organization.

Today there is the let and const to declare variables, which give error if the variable is declared twice within the same scope or block.

With var scenarios of these are possible:

var a = 10;
// outras linhas de código aqui...
// e depois, misturado algures dentro da mesma função:
var a = function(){}

that is, we can in the same scope declare a twice without being warned that the first a was over-written!

If we put all variable statements at the beginning of the scope, it would be easier to detect this:

var a = 10;
var a = function(){} // <--- oops, "a" já foi declarado
// outras linhas de código aqui...

With let or const the code above would be wrong:

Uncaught Syntaxerror: Identifier 'a' has already been declared

The other reason is hoisting. That is, in practice variables are declared at the top of the scope. Even if we have var a = b; in the middle of the code the Javascript interpreter will always read this way:

var a; // declares and stands as helpless // the rest of the code a = b; // value is assigned only when execution reaches that code line.

example:

console.log(a); // undefined
try {
    console.log(b); // vai dar erro
} catch (e) {
    console.log(e); // erro: ReferenceError: b is not defined
}
var a = 10;
console.log(a); // 10

Now to avoid confusion and for the code to reflect what happens inside the interpreter, it is advised to declare the variables at the top of the scope/block.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.