A few months ago, I saw a partner’s question in the study group, but no one answered him because other leaders discussed other questions. Therefore, I chose to study by myself, consult materials, and give him answers. Meanwhile, I wrote this article and put it on my blog.
Today, a friend asked me the same question, so I decided to send the article to the nuggets, hoping to get their advice, my analysis process is cumbersome, feel uncomfortable can directly jump to the analysis principle. (won’t be an anchor for the Nuggets…)
Problem of repetition
Take a look at his question:
First code:
if (true) {
a = 3;
function a() {};
console.log(a)
};
console.log(a);
// Prints the result as
/ / 3
/ / 3
Copy the code
The second code:
if (true) {
function a() {};
a = 3;
console.log(a)
};
console.log(a);
// Prints the result as
/ / 3
// [Function: a]
Copy the code
At first glance nothing special, but if you think about it, in the second code, there is no change to variable A after assignment a = 3, and the last printed result is a [Function: a].
This made me feel very strange as a young practitioner, and started my way of solving problems.
Try to problem solving
I first decompose the problem step by step (there may be a lot of people will think I do a lot of trouble, but I still used to step by step to correct mistakes)
First code:
if (true) {
a = 3;
function a() {};
console.log('If inside print:', a)
};
console.log('If out of print:', a);
// Print in if: 3
// Print outside of if: 3
Copy the code
The second code:
if (true) {
function a() {};
a = 3;
console.log('If inside print:', a)
};
console.log('If out of print:', a);
// Print in if: 3
[Function: a]
Copy the code
From here I get the result that the print outside the if statement is different
Then I use my parsing method to find out where the value of a becomes [Function: a].
First code:
console.log('Initial print', a);
if (true) {
console.log('Enter print of if', a);
function a() {};console.log('Declare function print', a);
a = 3;
console.log('Print assignment inside if', a)
};
console.log('Print out of if', a);
// Initially print undefined
[Function: a]
// Declare Function print [Function: a]
// Print the assignment inside if 3
[Function: a]
Copy the code
The second code:
console.log('Initial print', a);
if (true) {
console.log('Enter print of if', a);
a = 3;
console.log('Print assignment inside if', a)
function a() {};console.log('Declare function print', a);
};
console.log('Print out of if', a);
// Initially print undefined
[Function: a]
// Print the assignment inside if 3
// Declare the function to print 3
// Print out if 3
Copy the code
Here I see two clues
The first point:
Based on my understanding of function promotion, js will promote the whole function declared by function keyword during pre-parsing, while declaring a function expression with var will only promote the variable name and assign undefined, just like the following
console.log(sayHi);
function sayHi() {};// [Function: sayHi]
console.log(sayNo);
var sayNo = function () {}// undefined
Copy the code
In my previous code, the way to declare the function is keyword declaration, but the initial print content is undefined, which does not conform to the characteristics of function promotion, but with var declaration function expression variable promotion characteristics are consistent.
The second point:
The print immediately following the assignment inside the two if statements is the normal assignment, but the print outside the if statement is not affected by the assignment inside the if statement, just as if the if statement also has block-level scope. However, both the knowledge I have learned and the article I have read on site tell me: Js has only global scope and function scope.
Javascript is divided into Global context: window/Global and Local Scope (also known as Function context). Simply put, a scope is the generation environment or context of the current function, containing variables defined in the current function and references to the outer scope
That is, the if statement has no scope of its own, which makes me more confused.
The third point:
The first two points did not help me too much, but made me more confused, so I can only start from the third point, that is:
The print outside of if is always the same as when the function was declared
Is the global variable a already defined when the function is declared?
Also, while looking through the MDN documentation on Function, I found an interesting point (portal) :
In the “conditional creation of functions” section of the MDN documentation on function, it says:
Functions can be declared conditionally, which means that a function declaration may appear in an if statement, but this declaration may have different effects in different browsers. Therefore, you should not use this declaration in your build environment code and should use functional expressions instead.
It was officially opposed to using keywords in if conditional statements to declare functions, but from the documentation and other bits and pieces of knowledge, my thinking gradually became clear.
Analyze the principle of
Based on my previous three points, I’ll go through them step by step
3.1 Problems of function promotion
First of all, there is no problem with my original knowledge. When the function keyword is used to declare a function, the function will be promoted during pre-parsing, so we can call the function before the real function declares the code block.
However, one of the characteristics of if conditional statements is that they are conditional. If the function keyword declaration is used in the if conditional statement, the if condition will not be judged during the pre-parsing. That is to say, if it improves the function function declaration, it will cause that when the if condition is not standing, This is equivalent to a function that is undeclared but can still be called because it has been promoted, which creates a very serious Bug.
Therefore, in actual JS pre-parsing, functions declared with keywords in if conditional statements will have their names elevated and assigned to undefined (as if they were converted to literals).
3.2 Block-level scope artifacts for if conditions
Immediately after the end of 3.1, the function name is promoted and undefined is assigned, and the entire function declaration is promoted to the top level of the if condition, just like function promotion in block-level scopes.
Function a(){}; function a(){}; A block of code assigns the content of the variable named A to the global variable of the same name.
The subsequent assignment to a is actually an assignment to the top-level function declared in the if statement, without affecting the global variable A.
That’s why the following assignment doesn’t affect the last print outside of if.
At the same time, my third point is answered, the reason why the print outside of if is always the same as the print outside of the declaration function is that when the declaration function is encountered, its promotion to global a is assigned, so of course they are the same.
Light text is certainly not easy to understand, LET me on a few pictures
1.
2.
Through the comparison of the two pictures above, the knowledge point is very clear.
Take a chestnut
Fortunately, there is a friend in the group sent a same problem, I take here for example.
His code block:
His printouts
His question:
Why not undefined?
F =a, a is declared globally, but it’s not assigned, it’s undefined, and then it’s copied to f, so f was a function, but now it’s undefined, log, so that’s undefined
Answer time ~
When a function is declared with a keyword in if(true), the top level of variable promotion is equivalent to that in js pre-parsing
/ / global
var a = undefined;
var f = undefined;
Copy the code
In the if statement, function f(){… } is promoted to the top level, where the variable f contains the entire function.
And when js reads the real function f(){… }, f is still the whole function, so the global variable f is assigned to the whole function, so its last print is the whole function, not undefined.
So how do you make the last entry print undefined? Function f(){function f(){… };};};};
var a;
if (true) {
f(); // Bring the calling function here
function f() {
f = a;
console.log('Function completed'); }}// f()
console.log(f);
Copy the code
If you are interested in GYM, you can print it to see if it is undefined.
The end, the meeting ~~