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).
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 variablehello
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 calledhello
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
say
) is calledconsole.log(hello)
executes
hello
contains "Hello World !!"
at that point"Hello World !!"
gets printedYou 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.