The first article mentions the promotion of variables, so let's talk about variable elevation and function promotion today. This knowledge point is a cliché, but some of the details of the blogger would like to take this opportunity to summarize.
Today we mainly introduce the following points:
1. Variable Promotion
2. Function Promotion
3. Why do you want to promote
4. Best practices
So, let's get into the subject.
1. Variable Promotion
Usually the JS engine will be pre-compiled before it is formally executed, and in this process, the variable declaration and function declaration are first promoted to the top of the current scope, followed by the next processing. (Note: The current popular JS engine most of the source code has been compiled, due to different engines, the compilation will vary, we say that the pre-compilation and promotion is actually abstract, easy to understand the concept)
In the following code, we declare a variable in the function, but the variable declaration is in the IF statement block:
function hoistvariable () { if (! Foo) { var foo = 5; } // 5}
Hoistvariable ();
Run the code, we will find that the value of Foo is 5, beginners may not understand this, if the outer scope also has a Foo variable, it is more confusing, it is not to print the outer scope of the Foo variable it? The answer is: No, if this variable declaration exists in the current scope, no matter where it is declared, referencing the variable will find it in the current scope and will not go to the outer scope.
So as for the printing results, this refers to the pre-compilation mechanism, after a pre-compilation, the above code logic is as follows:
// after pre-compilation function hoistvariable () { var foo; if (! foo) { = 5; } // 5 }hoistvariable ();
Yes, the engine promoted the variable declaration to the top of the function, the initial value is undefined, naturally, if statement block will be executed, the Foo variable is assigned a value of 5, the following printing is the expected result.
Similarly, here's an example:
var foo = 3; function hoistvariable () { var foo = Foo | | 5; // 5 }hoistvariable ();
Foo | | 5 The result of this expression is 5 instead of 3, although there is a Foo variable in the outer scope, but the function is not referenced, because the code logic after precompilation is this:
var foo = 3; // after pre-compilation function hoistvariable () { var foo; = Foo | | 5; // 5 }hoistvariable ();
If more than one variable with the same name is declared in the current scope, then according to our inference, their same identifier is promoted to the top of the scope, and the other parts are executed sequentially, such as the following code:
function hoistvariable () { var foo = 3; { var foo = 5; } // 5 }hoistvariable ();
Since JavaScript has no block scope, only global scope and function scope, the pre-compiled code logic is:
// after pre-compilation function hoistvariable () { var foo; = 3; { = 5; } // 5 }hoistvariable ();
2. Function Promotion
I believe you are not unfamiliar with the following code, the actual development is also very common:
function hoistfunction () { // output:i am hoisted function foo () { Console.log (' I am hoisted ');} } Hoistfunction ();
Why the function can be called before the Declaration, and unlike the variable declaration, it can also get the correct result, in fact, the engine is the function declaration is raised to the top of the current scope, the pre-compiled code logic is as follows:
// after pre-compilation function hoistfunction () { function foo () { console.log (' I am hoisted '); } // output:i am hoisted }hoistfunction ();
Similarly, if there is more than one function declaration with the same name in the same scope, subsequent occurrences will overwrite the preceding function declaration:
function hoistfunction () { function foo () { console.log (1); } // output:2 function foo () { Console.log (2); }} Hoistfunction ();
For the function, in addition to using the function declaration above, we will use the function expression, the following is the comparison of function declaration and function expression:
// function declaration Foo () {console.log ( ' function declaration ' );} // anonymous function expression var foo = () {Console.log ( ' anonymous function expression ' // named function expression var foo = bar () {Console.log ( ' named function expression '
As you can see, the anonymous function expression, in fact, is to assign a non-named function declaration to a variable, and the named function expression, the name of the function is assigned to a variable, it should be noted that the function name can only be used inside this function. We also see that function expressions can be accessed through variables, so there are also variables that promote the same effect.
So what happens when a function declaration encounters a function expression, first look at the following code:
function hoistfunction () { // 2 varfunction() { Console.log ( 1); }; // 1 function foo () { Console.log (2); } // 1 }hoistfunction ();
After the operation we will find that the results of the output is 2 1 1, then why is there such a result?
Because a function in JavaScript is a first-class citizen, the function declaration has the highest priority and is promoted to the top of the current scope, so the function declaration defined below is actually executed at the time of invocation, and then the second invocation, because the preceding function expression has the same name as the previous function declaration, it is overwritten, Subsequent calls will also print the same result. After the above procedure has been precompiled, the code logic is as follows:
// Hoistfunction () { var Span style= "color: #000000;" > Foo; Foo = function Foo () {Console.log (2); } foo (); // 2 = function () {Console.log (1); }; Foo (); // 1 // 1
It is not difficult to understand how the following functions and variables will be executed when they have the same names:
var foo = 3; function hoistfunction () { // function foo () {} = 5; // 5 function foo () {}}hoistfunction (); Console.log (foo); // 3
We can see that the function declaration is promoted to the top of the scope, then assigned to 5, the outer layer of the variable is not overwritten, after precompilation, the logic of the above code:
// after pre-compilation var foo = 3; function hoistfunction () { var foo; function foo () {}; // function foo () {} = 5; // 5 }hoistfunction (); Console.log (foo); // 3
Therefore, the priority of the function is the highest, it is always promoted to the top of the scope, and then the function expression and variables are executed sequentially, this is to bear in mind.
3. Why do you want to promote
There's no clear answer to why you're doing variable promotion and function promotion, but the last time I read an article before Dmitry Soshnikov, I learned a little bit about it, and here's Dmitry Soshnikov's earlier Twitter, He is also very interested in this issue:
Then Jeremy Ashkenas want to let Brendan Eich talk about this topic:
Finally, Brendan Eich gives the answer:
The general meaning is that because of the abstract flaws in the first-generation JS virtual machine, the compiler places the variable in the stack and indexes it, and then binds the variable name to the variable in the stack at the entrance (current scope). (Note: The abstraction mentioned here is computer terminology, a simplification of the more complex things that happen inside.) )
Then, Dmitry Soshnikov mentions the function promotion, he mentions reciprocal recursion (that is, the a function calls to the B function, and the B function calls to the A function):
Then Brendan Eich was very enthusiastic and gave the answer:
Brendan Eich is quite certain that the function promotion is to solve the problem of mutual recursion, in general, can solve the bottom-up order problem like ml language.
Here is a brief explanation of reciprocal recursion, and the following two functions call each other in their own function body:
//Verifying even numbersfunctionIsEven (n) {if(n = = 0) { return true; } returnIsOdd (n-1);} Console.log (IsEven (2));//true//Verify Oddfunctionisodd (n) {if(n = = 0) { return false; } returnIsEven (n-1);}
If there is no function promotion, but in the bottom-up order, when the IsEven function is called, the isodd function is not declared, so the isodd function cannot be called within IsEven. So Brendan Eich designed the form of function promotion to elevate the function to the top of the current scope:
//Verifying even numbersfunctionIsEven (n) {if(n = = 0) { return true; } returnIsOdd (n-1);}//Verify Oddfunctionisodd (n) {if(n = = 0) { return false; } returnIsEven (n-1);} Console.log (IsEven (2));//true
In this way, the problem is solved.
Finally, Brendan Eich also summarizes the variable promotion and function promotion:
Presumably, variable promotion is a man-made problem, and function promotion has a purpose at the time of design.
Now, with respect to variable promotion and function promotion, I believe you have understood the truth.
4. Best practices
Understanding variable elevation and function promotion allows us to better understand the language and harness it, but in development we should not use these techniques, but rather standardize our code to be readable and maintainable.
The specific practice is that both the variable and the function must be declared before being used. Here's a simple example:
var name = ' Scott '; var function (Guest) { ' says hello to ', guest);}; var i; var Guest; var guests = [' John ', ' Tom ', ' Jack ']; for (i = 0; i < guests.length; i++) { = guests[i]; // Do something on guest SayHello (guest);}
If you can replace Var with let with a new project, it becomes more reliable and maintainable:
Let name = ' Scott 'function(guest) { ' says hello to '= [' John ', ' Tom ', ' Jack ' ]; for (Let i = 0; i < guests.length; i++) { = guests[i]; // Do something on guest SayHello (guest);}
It is worth mentioning that the class declaration in ES6 also has an elevation, but it is like let, const, is constrained and restricted, its provisions, if the declaration position before the reference, it is illegal, will throw an exception.
So, whether it's early code or code in ES6, we all need to follow a little, first declare, then use.
The end of this article.
Resources:
Http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html
http://dmitrysoshnikov.com/notes/note-4-two-words-about-hoisting/
https://javascriptweblog.wordpress.com/2010/07/06/function-declarations-vs-function-expressions/
Http://stackoverflow.com/questions/7506844/javascript-function-scoping-and-hoisting
JavaScript series articles: variable promotion and function promotion