0

case 1: I understand why it works in this case:

function foo(arg) {
  var outer = " this is the outer variable";
  function bar() {
    console.log("arg: " + arg);
    console.log("outer variable: ", outer);
  }
  bar();
}

console.log(foo("hello"));

case 2: But I don't understand why the following doesn't work if declare the bar function outside, separately:

function foo(arg) {
  var outer = " this is the outer variable";

  bar();
}

function bar() {
  console.log("arg: " + arg);
  console.log("outer variable: ", outer);
}

console.log(foo("hello"));

case 3: If I add arguments to bar function:

function foo(arg) {
  var outer = " this is the outer variable";

  bar();
}

function bar(arg, outer) {
  console.log("arg: " + arg);
  console.log("outer variable: ", outer);
}

console.log(foo("hello"));

The output:

"arg: undefined"
"outer variable: " undefined

My question is regarding the case 2: why bar() doesn't reach the variables defined inside the foo()?

Edit case 2:

Have learnt from all feedbacks, I have added arguments to bar(arg, outer), and it works. Thanks a lot.

function foo(arg) {
    var outer = " this is the outer variable";

    bar(arg, outer);
}

function bar(arg, outer) {
    console.log("arg: " + arg);
    console.log("outer variable: ", outer);
}

console.log(foo("hello"));

It works.

Saifur
  • 16,081
  • 6
  • 49
  • 73
juanli
  • 583
  • 2
  • 7
  • 19
  • Let's ask the other way around. Why do you *assume* that `bar()` can reach the variables defined inside `foo()`? – Tomalak Feb 12 '18 at 09:07
  • You're not passing the variables to bar both for the case 2 and 3, the outer is a local only available to foo and so is the arg. Calling the bar inside foo doesn't mean that bar will have access to the local variables. – null Feb 12 '18 at 09:07
  • @Tomalak Because the lexical scoping, I assume the nested function can reach the variables defined inside the outer function. – juanli Feb 12 '18 at 09:09
  • But in your second example there is no nesting, is there? (Calling a function inside another function is not the same as defining a function inside another function) – Tomalak Feb 12 '18 at 09:12

7 Answers7

1

Function parameters are visible only inside the declaring function

So bar function cannot access foo's parameters

You should pass the parameter to foo function

function foo(arg) {
  var outer = " this is the outer variable";

  bar(arg); //<-------------
}

function bar(arg, outer) {
  console.log("arg: " + arg);
  console.log("outer variable: ", outer);
}
nemo
  • 1,675
  • 10
  • 16
1

Because the lexical scope of bar is defined by its position in code, not the chain through which it is executed. Let me quote wikipedia on the subject:

A fundamental distinction in scoping is what "part of a program" means. In languages with lexical scope (also called static scope), name resolution depends on the location in the source code and the lexical context, which is defined by where the named variable or function is defined. In contrast, in languages with dynamic scope the name resolution depends upon the program state when the name is encountered which is determined by the execution context or calling context.

In practice, with lexical scope a variable's definition is resolved by searching its containing block or function, then if that fails searching the outer containing block, and so on, whereas with dynamic scope the calling function is searched, then the function which called that calling function, and so on, progressing up the call stack.[4] Of course, in both rules, we first look for a local definition of a variable.

In other words, were you to declare bar inside foo its lexical scope would include foo's lexical scope.

Rovanion
  • 4,382
  • 3
  • 29
  • 49
1

No matter where a function is invoked from, or even how it is invoked, its lexical scope is only defined by where the function was declared.

function foo(arg) {
  var outer = " this is the outer variable";
  function bar() {
    console.log("arg: " + arg);
    console.log("outer variable: ", outer);
  }
  bar();
}

Here bar can access outer variable as it is in its lexical scope but not in the case 2.

void
  • 36,090
  • 8
  • 62
  • 107
  • "its lexical scope is only defined by where the function was declared." very important message for me. I don't get this from some online course. Or I might miss this part. Thanks a lot. – juanli Feb 12 '18 at 09:29
1

I suggest you read up on this https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var

The scope of a variable declared with var is its current execution context, which is either the enclosing function or, for variables declared outside any function, global.

outer is encapsulated within foo so there is no reference to it outside of that function.

try passing it as a param

var outer = 'global var';

function foo() {
  var inner = "this is the inner variable";
  bar(inner);
}

function bar(arg) {
  console.log("arg: " + arg);
  console.log("outer var: " + outer);
}
Adam Wareing
  • 206
  • 2
  • 5
1

When bar is defined, its scope chain is created, preloaded with the global variable object, and saved to the internal [[Scope]] property. When bar is called, an execution context is created and its scope chain is built up by copying the objects in the function’s [[Scope]] property

so,if you give bar two arguments arg,outer,that is gonna work:

function foo(arg) {
  var outer = " this is the outer variable";

  bar();
}

function bar(arg,outer) {
  console.log("arg: " + arg);
  console.log("outer variable: ", outer);
}

console.log(foo("hello"));

Professional JavaScript for Web Developers.3rd.Edition.Jan.2012

p222

xianshenglu
  • 4,943
  • 3
  • 17
  • 34
  • The code doesn't work. I have tried in console, which turned out: undefined variables. – juanli Feb 12 '18 at 09:19
  • i got no error,got undefined because bar() didn't pass the arguments,get it?@Amy – xianshenglu Feb 12 '18 at 09:24
  • if you want to know better about scope and closure,suggest you read that book,that is awsome – xianshenglu Feb 12 '18 at 09:26
  • You're right. I really need a solid book regarding JavaScript to improve my professional skills. I found it in amazon.de (https://www.amazon.de/Professional-JavaScript-Developers-Wrox-Guides/dp/1118026691/ref=sr_1_1?ie=UTF8&qid=1518427877&sr=8-1&keywords=Professional+JavaScript+for+Web+Developers) but do you think Edition 2012 is a little outdated? I mean now we have ES6 standard for JS. – juanli Feb 12 '18 at 09:36
  • ES6 i have read 《Understanding ECMAScript 6》.To be honest,i think better read 《JavaScript The Definitive Guide 6rd Edition》and 《Professional JavaScript for Web Developers.3rd.Edition.Jan.2012》first.Actually, the last two books include mostly knowledge before ES6.And if you know ES5 ,ES3 and the history,it will help you a lot to understand ES6.Also you should know,ES6 just add something new to js,it doesn't overwrite js.However, those two books before ES6 was huge,you can read one first , though i would suggest that you can read it all if you have time. – xianshenglu Feb 12 '18 at 09:49
  • Highly appreciate your recommendations. I will definitely buy these two books to read. Have such professional developer books by side must be very beneficial. Thanks again. – juanli Feb 12 '18 at 09:57
  • I guess you might be Chinese as you use << ..>> symbols. Me too. I'm looking for a web developer job recently. A big career change in my life. – juanli Feb 12 '18 at 09:58
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/164957/discussion-between-xianshenglu-and-amy). – xianshenglu Feb 12 '18 at 10:52
0

My question is regarding the case 2: why bar() doesn't reach the variables defined inside the foo()?

outer is declared as a var, which means it has function scope (it is accessible inside the function in which it is declared).

Therefore, outside foo (in bar), outer is not accessible unless it is declared in bar or at its parent scope (function in which bar is declared).


From comment

I assume the nested function can reach the variables defined inside the outer function.

  • Confusion seems to be stemming from the idea that bar is nested inside foo - which is wrong.

  • bar is not private to foo since it is not declared inside foo, it is declared in the same scope as foo.

gurvinder372
  • 66,980
  • 10
  • 72
  • 94
0

You are not passing the necessary argument to the bar function, the third undefined is because you are not returning nothing in the functions, this will work:

function bar(arg, outer) {
  console.log("arg: " + arg);
  console.log("outer variable: ", outer);
  return arg + outer;
}

function foo(arg) {
  var outer = " this is the outer variable";

  return bar(arg, outer);
}

console.log(foo("hello"));