0

I read a number of articles about the javascript scope chain and I thought I had a decent understanding of it. However, a very simple exercise made me realize I do not yet understand it at all.

I created the following code.

function foo () {
  var b = 2;

  bar()

} 

function bar () {
  console.log(b);

}

foo();

This code gives a reference error. However, I assumed that it would still print out 2. My reasoning was the following:

  • Function declaration of foo and bar.
  • Foo is executed, this creates a new execution context. Foo has internal property [[Scope] set to global.
  • var b is hoisted.
  • var b is assigned 2.
  • bar is executed inside of the foo execution context. Therefore, I assumed the internal property [[Scope]] of the bar function would be set to foo.
  • b is not defined in function bar, therefore the scopechain is looked up and finds the value b = 2.
  • console.log(2);

My reasoning is based on that I understand that the [[Scope]] internal property of function X is set to the execution context that is running at the time function X is executed. Not based on where function X is declared.

Jack Spar
  • 523
  • 1
  • 5
  • 6

2 Answers2

3

b is defined in foo's scope.

bar is called from foo's scope, yes, but it's defined outside of foo's scope. This means that bar can not access b.

As an image can often help:

enter image description here

Consider each red square to be a "scope". foo and bar share the outer scope, but they can't access each other's inner scope.

Cerbrus
  • 70,800
  • 18
  • 132
  • 147
  • Cerbrus thank you for the very quick response. The part that got me confused is this question asked on stackoverflow. http://stackoverflow.com/questions/21128496/javascript-when-does-the-scope-chain-created. The way you describe it, it seems to me that the scope chain is determined by the execution context in which the function is declared, i.e. its lexical environment, not determined by in which execution context the function is called. However, the answer to the linked question seems to suggest the latter? – Jack Spar May 03 '17 at 11:54
  • @JackSpar: I'm not sure what the last line in that answer is implying. Kinda hard to say without an example. The one thing I'm sure of is that `b` isn't accessible because it's in `foo`'s scope. – Cerbrus May 03 '17 at 11:58
  • Ok great, then I think I understand you. Just to confirm my understanding. The below code would not be considered a closure (the way programmers usually speak about it) as function baz should already have access to the scope of function foo as it is defined/declared there? http://jsbin.com/nixitocuhi/edit?js,console – Jack Spar May 03 '17 at 12:00
  • @JackSpar: That works because `baz` is defined in the same scope `a` is in. You can also expose `baz` from the global scope, and still make it log `a`: `function foo() { var a = 2; function baz() { console.log( a ); } return baz; } var alias = foo(); alias();` – Cerbrus May 03 '17 at 12:03
  • Perfect! Thank you so much :) – Jack Spar May 03 '17 at 12:51
1

Let me write your code in a different manner, to account for the scope.

var scope = {};
scope.foo = function() {
  var b = 2;   
  scope.bar()   
} 

scope.bar = function() {
// this will look for a property 'b' defined in the bar method, but it doesn's exist
  console.log(b); 
// changing the console.log call to match the changes made above, means it will 
// look like this
  console.log(scope.b)
// but now scope.b is also not defined
}

scope.foo();

In other words, when you try to access 'b' inside 'bar', it will search for it in the scope where 'bar' was created, not in the scope where 'bar' is called.