0

I want to know the difference between the following two block of codes:

function foo() {
    var a = 'private variable';
    return function a(){
        console.log(a) 
    }
}
foo()(); // output: function a(){...}

vs

function foo() {
    var a = 'private variable';
    function a(){};
    return () => {console.log(a)} 
}
foo()(); // output: private variable

In the first block of code, based on the hoisting, the function a definition should be hoisted, and then var a = 'private variable' rewrite the a, but why the console.log(a) output the function definition?

VLAZ
  • 26,331
  • 9
  • 49
  • 67
Jiajia
  • 31
  • 2
  • I think this will help you http://perfectionkills.com/understanding-delete/ – Thakur Karthik Jun 25 '20 at 10:16
  • There is some concept of activation object which sets the property of a variable in a scope be it in global,function or eval scope..each have it's own rules for the final value of property. – Thakur Karthik Jun 25 '20 at 10:18

3 Answers3

0

In the first case when you are referencing a in console.log you are actually referencing the function a and it already shadowed over the var = a so you don't have access to it.

On the second option, function a() {} actually moves above the var a = 'private variable' so the code would look like this:

function a() {};
var a;
a = 'private variable';

That is why when you call foo()() your var a = 'private variable'; is shadowing over the function a and you see private variable in terminal.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Evgeny Klimenchenko
  • 1,184
  • 1
  • 6
  • 15
0

It's not about hoisting. The first variant does not actually declare a function, it is merely a function expression (i.e., a 'lambda' or a 'closure') which doesn't declare anything within it's own lexical scope. What the 'a' does in that expression is assign the 'name' property of the resulting function object, and make it available to it's body's lexical scope:

e.g. in node:

> const f = function a() {console.log(a);}
undefined
> a
Thrown:
ReferenceError: a is not defined
> f
[Function: a]
> f()
[Function: a]
undefined

See also https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function

Gerard van Helden
  • 1,601
  • 10
  • 13
0

I hope below code could help you understand what is happening.

When you use return function a() { ... } it will not considered as function declaration but will be treated as Variable assignment like a = function () { ... }; return a;. And return will execute later a will hold value as function.

As below code you can be sure that assignment want take place until it reaches that line. So when we use foo(1)(); it outputs private variable.

function foo(returnString) {
  var a = 'private variable';
  if (returnString)
    return function() { console.log(a); };
  return function a() { console.log(a); };
}
foo()(); // output: function a() { console.log(a); }
foo(1)(); // output: private variable

In your second case it is quite simple. As per Order of precedence

  1. Variable assignment takes precedence over function declaration
  2. Function declarations take precedence over variable declarations

function foo() {
  var a = 'private variable';
  function a() {};
  return () => { console.log(a); }
}
foo()(); // output: private variable
Karan
  • 12,059
  • 3
  • 24
  • 40