-1

I am learning about javascript closure, I have this program

var x = 1;

function f1(){
  console.log(x);
}

f1()

function f2(){
  var x = 100;
  f1();
}

f2()

It prints

1
1

But according to my understanding it should print

1
100

Since, the second time f1() is being executed inside f2()'s execution context where x is 100, also needless to say var is function scoped. So why is it printing 1 istead of 100?

  • An inadvertent lesson in why global variables are bad. – David Thomas May 29 '21 at 10:15
  • Because f1 prints the value from the closure where f1 is created (not invoked). More about closures: https://javascript.info/closure – Rango May 29 '21 at 10:19
  • You must notice to `global variable` vs `local variable`. The first `x` is global and the second one is local and your function show the global `x` but you change the local variable. – Alireza Ahmadi May 29 '21 at 10:57
  • 3
    What you are asking about is the difference between [Lexical and Dynamic scoping](https://stackoverflow.com/questions/1047454/what-is-lexical-scope) – Drdilyor May 29 '21 at 11:07
  • @Drdilyor maybe you want to write an answer around that link because I think you are much more on point with that than I was in my answer (I didn't know about dynamic scoping existing in other languages) – CherryDT May 29 '21 at 12:58

4 Answers4

4

In Javascript a function can access variables from the scopes when it is defined, not called. In other words, It doesn't matter where the function is called, but where is defined - does matter.

I would suggest reading this article/book, but Russian one is more comprehensive


This is called Lexical Scoping, There are some languages that would do the opposite: it doesn't matter where the function is defined, all scopes function can access depends where the function is called. This is called Dynamic Scoping

miken32
  • 42,008
  • 16
  • 111
  • 154
Drdilyor
  • 1,250
  • 1
  • 12
  • 30
3

f1 doesn't have its own x, so it refers to the global x, which is 1 and you never change it. f2 does have a local x in scope which it refers to, which is 100, but there is no code in f2 that ever refers to it! The only console.log you have is in f1, referring to the global x, and you are calling it twice (once from the top-level code and once from inside f2, but where it's called from doesn't matter)

You are saying the second time f1 is called from f2's execution context but that doesn't matter, when you call a function a new execution context is created and f2' s won't have f1's variables in scope (in its lexical environment to use the correct term here) unless you would nest the whole definition of f1 into f2. The scopes are fixed* at compile time, they won't change at runtime based on the call stack.

*: In terms of their variables' location in the source code. Since every invocation of a function creates a new scope where those local variables can have new values, technically it is of course set at runtime, but it would still be the same var/let/etc in the source code that is referred to every time.

See also: https://javascript.info/closure (this has a great explanation, as already mentioned by Andrejs Kuzmins in the comments)

CherryDT
  • 25,571
  • 5
  • 49
  • 74
  • " unless you would nest the whole definition of f1 into f2. " that makes sense. So you are saying f1() in f2() here is not a closure? – Probhakar Sarkar May 29 '21 at 10:22
  • 1
    Exactly. Note that when you _would_ nest the definitions, then `f1` would instead no longer be callable from the top-level code since it wouldn't be in scope there, and also you would technically get a new, different `f1` every time `f2` is invoked because it would refer to a different execution context in a parent scope every time (you could return the nested function from the outer function and reference it later and it would still use the same `x` it had originally even if you had invoked `f2` several more times since then, let's say with a `x = Math.random()` in it) – CherryDT May 29 '21 at 10:26
0

Cancel var in f2 function

var x = 1;

function f1(){
  console.log(x);
}

f1()

function f2(){
  x = 100;
  f1();
}

f2()
Evren
  • 4,147
  • 1
  • 9
  • 16
  • Okay thank you, but can you describe in terms of execution context, why the first approach is giving 1,1? – Probhakar Sarkar May 29 '21 at 10:20
  • This doesn't answer the question why `f2`'s `x` isn't in scope inside of `f1` when invoked from inside `f2` – CherryDT May 29 '21 at 10:22
  • Okay i did not give description but what is the reason of giving downvote since I gave working solution? @CherryDT – Evren May 29 '21 at 10:29
  • 1
    The reason was that the OP didn't ask for a way for it to print 1 and 100 but instead they asked why it printed 1 and 1 and what is wrong in their understanding of closures. You didn't answer the question but instead provided a solution for a non-problem that wasn't asked. – CherryDT May 29 '21 at 10:44
-4

Using var in statement var x =100 initializes another variable that is not in scope for f1 so remove the var Just x =100 will give the desired result.

TanviD
  • 1