Confusing behavior in changing the value of variables in js functions

Asked

Viewed 81 times

-1

Why time1 print 3 and time2 print 2?

let gols = 1

const time1 = function () {
    console.log(gols)
    gols = 2
}

gols = 3

const time2 = function () {
    console.log(gols)
}

time1() // 3
time2() // 2

3 answers

4

This has nothing to do with closure, including this way that has spread around declaring the function is horrible because it gives the wrong idea of what it is, when it has a simple function, use a simple function, only add complexity when necessary. If it were a closure the behavior would be different in certain scenarios. No anonymous function is equal:

let gols = 1

function time1() {
    console.log(gols)
    gols = 2
}

gols = 3

function time2() {
    console.log(gols)
}

time1() // 3
time2() // 2

The problem is finding that the code is running in order that you read.

The execution of it actually goes like this:

const time1 = function () {
    console.log(gols)
    gols = 2
}

const time2 = function () {
    console.log(gols)
}

let gols = 1
gols = 3
time1() // 3
time2() // 2

I put in the Github for future reference.

Everything in the same context runs together. Note that the above functions are only declared, they are not executed until your call. The overall context, that is, outside of some function is one thing and the declarations are not executed.

The variable gols is global. Nothing in the let indicates it is not. Maybe you’re confusing this. It was declared in a global context, so it has scope and is visible globally. Anywhere that changes its value will affect everything.

So what happens there is that:

  • declares a function
  • declares the other
  • declares a variable gols with a value
  • soon after the value is changed
  • and calls one of the functions. Since this function internally refers to the global variable, its value is currently used. And then the value is changed. The variable is global, then the global value is changed. The next variable access anywhere in the application will see this new value.
  • then access the value global again in another role.

This is just one of the reasons not to use the global variable. It doesn’t work as people expect. There is a loss of control of where it is changed. If in simple code causes confusion imagine in a complex.

2

As said in the comments make a table test to understand what program is doing step by step.

In this test are four columns Code, goals, output and comment, where:

  • Code: shows the line being executed.
  • goals: shows the value of the variable goals after the execution of Code.
  • exit: shows the console output due to the use of console.log().
  • Commentary: an auxiliary comment of what the code is doing.

Each line represents a step of the algorithm’s functioning:

+------------------------------------+----------+-------+---------------------------------+
| Código                             |   gols   | saída |            Comentário           |
+------------------------------------+----------+-------+---------------------------------+
| let gols = 1                       |     1    |       | declara gols com valor 1.       |
+------------------------------------+----------+-------+---------------------------------+
| const time1 = function () {        |     1    |       | declara a função time1()...     |
+------------------------------------+----------+-------+---------------------------------+
|     console.log(gols)              |     1    |       |    declara o corpo da função.   |
+------------------------------------+----------+-------+---------------------------------+
|     gols = 2                       |     1    |       |    declara o corpo da função.   |
+------------------------------------+----------+-------+---------------------------------+
| }                                  |     1    |       | ...encerra declaração           |
+------------------------------------+----------+-------+---------------------------------+
| gols = 3                           |     3    |       | atribua 3 para gols.            |
+------------------------------------+----------+-------+---------------------------------+
| const time2 = function () {        |     3    |       | declara a função time2()...     |
+------------------------------------+----------+-------+---------------------------------+
|     console.log(gols)              |     3    |       |    declara o corpo da função.   |
+------------------------------------+----------+-------+---------------------------------+
| }                                  |     3    |       | ...encerra declaração           |
+------------------------------------+----------+-------+---------------------------------+
| time1()                            |     3    |       | executa time1()                   |
+------------------------------------+----------+-------+---------------------------------+
|     console.log(gols)              |     3    |   3   |    imprime o valor de gols      |
+------------------------------------+----------+-------+---------------------------------+
|     gols = 2                       |     2    |       |    atribua 2 para gols.         |
+------------------------------------+----------+-------+---------------------------------+
| time2()                            |     2    |       | executa time1()                   |
+------------------------------------+----------+-------+---------------------------------+
|     console.log(gols)              |     2    |   2   |    imprime o valor de gols      |
+------------------------------------+----------+-------+---------------------------------+

1

There is a difference between the definition of the function and the execution of the function.

When you do time1 = function () etc, is defining the function. That is, it is only saying what it does, but at this point it still does not perform what is inside ("function, you must do this, but not now, only when I send").

When you do time1(), there yes it is performing the function ("function, you know what I said you should do? Do it now").

Then your code creates the variable gols with the value 1. Then sets the function time1, then changes the value of the variable to 3, then sets the function time2.

And only then do you perform time1, which prints the value of gols (which at that time is 3), and then changes the value to 2.

At last, you perform time2, which prints the value of gols, now worth 2.


Just for the record, you could have declared normal functions (function time1() { etc }), 'cause there’s no point in using a Function Expression - in this case it makes no difference in the result, but there are cases where it makes, see here.

And you’re not exactly wearing closures, read here and here to better understand.

Browser other questions tagged

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