I have two questions about hoisting:
The way function declarations are hoisted is that they go to the very top, even above variable declarations, to my understanding.
If we have this code:
function fn() {
callback();
}
function callback() {
console.log('why does this show');
}
I don't understand how this works, since both functions are hoisted to the top (which effectively produces the same code that already exists). But callback is still created below fn, and I don't see why we can access it in fn. My guess is it has something to do with the top level objects being able to access each other regardless of lexical position.
Similarly:
var a = 10;
function fn() {
console.log(a);
}
fn();
How does this work? Because the way I understand hoisting makes it seem like the function should be hoisted even above var a, which makes it seem like variables should always be inaccessible in functions.
CodePudding user response:
This is because how our Javascript Engine parse and compile the code.
I'm not an expert but V8 (The Chorme Engine for JS) in the first file get all the variables and functions names and store all the function references. So, you can "use" a function before "declare" because JS know where the function is.
Some languages, even C you could do that and is a nice feature :)
CodePudding user response:
We can go down the rabbit hole with this but I want to try to give a brief explanation on how your examples work.
Whenever the JavaScript engine creates an execution context (also known as calling stack) whether through functions or code in the global scope it creates an lexical environment. Which is a data structure that holds a collection of name/value pairs about variables and functions in it's own scope or from it's parent scope by using a reference.
If you call fn()
in your first example initially the global execution context 'sees' that. It will then add callback()
to the stack and execute that. So, the order of your functions don't really matter in this case.
You're second example is a different case and is more related to scoping. The execution context knowns you are referring to the global variable and therefor adding a reference to the lexical environment and that makes it able to use the variable inside fn()
.
This can be quite hard to get a grasp of. There are a ton of resources related to hoisting, scopes, lexical environments and execution contexts so be sure to check those out. :)