1

I understand that variable hoisting is the behavior of moving declaration to the top of the function or global context. This is shown in the code below:

console.log(a);
var a = 'Hello World!';

The above code actually gets the following behavior:

var a;
console.log(a);
a = 'Hello World!';

The resulting output from the above code is undefined.

In above example, it is important to note that variable hoisting moves only the declaration part at the top. The initialization part is not moved at the top.

When I am trying to replicate the same behavior using function expression, I am getting an unexpected output.

This is shown in code below:

function sayHello() {
    var say = function() { console.log(hello); }
    var hello= 'Hello World !!';
    return say;
}
sayHello()(); // output Hello World !!

I am trying to understand why we have not received undefined as an output because the variable hello is initialized only after it is used (similar to the previous example).

6
  • 1
    That's example 5 of stackoverflow.com/questions/111102/… The closure captures the variable reference (so to speak), not the value at the time of creation. Commented Apr 12, 2020 at 0:26
  • I don't think the comparison is fair. On one hand, you have a function that isn't invoked until after a var is initialized, and in another case, it's clearly uninitialized. The results don't seem surprising to me. Commented Apr 12, 2020 at 0:29
  • But here it's also not invoked before hello is initialized... Commented Apr 12, 2020 at 0:30
  • Exactly--seems like when sayHello() is called, everything in the closure is initialized, including hello. Then, say is invoked and of course it finds that hello has the value "Hello World !!" in its enclosing scope as we'd expect. Commented Apr 12, 2020 at 0:36
  • Yes that's what I'm saying... Seems I misunderstood what you meant. I thought you referred to the comparison to example 5 in the other answer, and then I read your isn't as is. Never mind Commented Apr 12, 2020 at 0:38

1 Answer 1

3

The behavior you see comes from how closures work. It's not that the value of hello somehow gets hoisted, it's that the code that reads the value of hello (the console.log(hello) part) is only executed after you set the value!

To not get confused here with the hoisting, since that is not really relevant to what you are seeing, let's write out the code in the way it would look after hoisting:

function sayHello() {
    var hello;
    var say = function() { console.log(hello); }
    hello = 'Hello World !!';
    return say;
}
sayHello()(); // output Hello World !!

If you would insert a say() before the line hello = 'Hello World !!'; it would print undefined.

Now, when you have code like this...

    var hello;
    var say = function() { console.log(hello); }

...then the hello inside say is not a copy of the outside hello, it's actually the same variable you are referencing here. And it continues existing even after the outer functioned returned, because now you have a reference to the say function which in turn still keeps a reference to hello.

I am trying to understand why we have not received undefined as an output because the variable hello is initialized only after it is used (similar to the previous example).

I think this is your misunderstanding. It is used when you call the say function at the very end - chronologically speaking. The fact that looking at the code from top to bottom hello appears to be "used" before doesn't matter, because that's not the order in which the code executes. At the line var say = function () { console.log(hello); } you just do var say = something;, the something doesn't have any meaning at that point (it just has to be syntactially correct). The access to hello occurs only when you call say at the end.

(You could also try with something like var say = function () { derp(); }, and you'd notice that you get the error derp is not defined only when you call that function, not when you define it.)

So, chronologically, this is what happens:

  • sayHello is called
  • hello is created and contains undefined
  • say is created and assigned a function expression with body console.log(hello)
  • hello is assigned "Hello World !!"
  • sayHello returns say
  • The function expression (which was say) is called
  • console.log(hello) executes
    • Remember that hello contains "Hello World !!" at that point
  • The string "Hello World !!" gets printed

You can expand this example, to help understanding:

function sayHello() {
  var hello;
  var say = function() { console.log(hello); }  
  hello = 'Hello World !!';
  var think = function() { hello = 'What should I think about?'; }
  return [say, think];
}

var [say, think] = sayHello();
say(); // Prints "Hello World !!";
think();
say(); // prints "What should I think about?"

As you can see, hello just lives on and can be used by both say and think, even after sayHello returned, all of these parts of the code reference the same hello variable.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.