0

I was trying to see how Lexical Scoping work within Javascript, So I tried below example. In my first example I am calling Test() within Main() and as expected it is giving error "bar" is undefined, similarly in second example I am calling setTimeout within Main(), but as again(setTimeout) it is function how it is able to get value of bar as Javascript has lexical scoping not Dynamic.

I am confused on this!!!

//Example No 1 without using setTimeout()

function Main()
{
   var bar = "Main";
   Test();
}

function Test()
{
  console.log(bar);
}

//Prints bar is undefined which is fine as it is Lexical Scoping and bar is 
//fine as there is no bar varibale in Test() or Global Context 
Main() 

//Example 2 with setTimeout()

var bar = "outside";

function main() {
 var bar = "Main";
 setTimeout(function() {
    console.log(bar);
 }, 1000)
}


//Prints value of bar = "Main"
main();
Michael Hutter
  • 1,064
  • 13
  • 33
user3045179
  • 321
  • 4
  • 20
  • @melpomene : Callback can be ignored for the second example, point is as callback is a function, setTimeout is also a function, so how setTimeout is able to access context of function from within which it is called and other normal function as Test() in my example is not, hope I make sense – user3045179 May 16 '18 at 19:48
  • Because of lexical scoping. Your second `console.log(bar)` is within the scope of `bar`. What's unclear? – melpomene May 16 '18 at 19:50
  • @melpomene :Then why not first one??. Both are function call inside a Main() – user3045179 May 16 '18 at 19:51
  • Because in the first one `console.log(bar)` is not within the scope of `bar`. The point is not where the call is made from; what matters is where the function body is located. – melpomene May 16 '18 at 19:52
  • Possible duplicate of [How do JavaScript closures work?](https://stackoverflow.com/questions/111102/how-do-javascript-closures-work) – Frax May 16 '18 at 19:59
  • @Frax : I have idea on Clousre, what I am missing was function passed as param to setTimeout will be finally part of main function I had intuition it will work like that but was not sure – user3045179 May 16 '18 at 20:02
  • 1
    Using setTimeout is actually completely irrelevant. Once you create a function (anonymous or not) it's name scope is fixed, once and for all. Is baked into the function object. Wherever you call it, it will use the same variables. – Frax May 16 '18 at 20:02

3 Answers3

1

Variables that remain in scope for a function are determined by where the function is defined, not where it is called.

In the first example, var bar is inside function Main but function Test is not so function Test does not have access to bar.

In the section example, var bar is inside function main and the anonymous function you pass to setTimeout is also inside function main. The anonymous function therefore has access to bar.

Quentin
  • 914,110
  • 126
  • 1,211
  • 1,335
  • But I am passing anonymous function as parameter to setTimeout , so as assumption anonymous function passed as param to setTimeout will be finally part of the Main() right ?? – user3045179 May 16 '18 at 19:59
  • @user3045179 — The anonymous function is defined inside `Main`, so it has access to the scope of `Main`. – Quentin May 16 '18 at 20:10
  • Got your point, my bad I missed that part, I thought anonymous function will be part of setTimeout – user3045179 May 16 '18 at 20:12
1

Let's simplify your second example, not using an anonymous function expression:

var bar = "outside";
function main() {
  var bar = "Main";
  function test() {
    console.log(bar);
  }
  test(); // or setTimeout(test, 1000) - doesn't matter
}
main();

The important thing here is that test is defined within the same lexical scope as the local var bar, so it can access it.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
1

Lexical scope is not about function call but function declaration. Inside function body you can access variables declared in every outer scope, but this is about declaration not the usage. In example with setTimeout you are declaring the anonymous function inside scope of main function, which has in scope bar variable, that is why the function inside setTimeout has lexical scope visibility of it and can access bar.

The first example doesn't work as you want because functions are declared on the same scope level, so Test and Main have the same outer scope, but Test has no access to Main and vice versa. The usage Test in Main has nothing to lexical scope, as I said the declaration of the function matters.

Maciej Sikora
  • 19,374
  • 4
  • 49
  • 50