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.