Expression evaluation Vs variable promotion

Halo, a dream shattered by a gentle alarm clock, I reluctantly opened the warm doghouse, picked up my phone and began the first phase of my daily routine: browsing.

Just when I was ready to finish browsing and go to wash -> have breakfast -> class, I saw a group friend in a certain communication group to initiate a question discussion, my hazy eyes instantly two eyes lit up, the whole person spirit up, and joined in the fierce discussion.

Topic recovery:

One group member took to a website to solve a dozen quirky and intriguing questions, and others joined in.

I also tried to do a ha, did a lot of mistakes:

Finally, the discussion on the right and wrong questions began, among which the most intense is the following question (corresponding to the 9th question in the website) :

var x = 1;

if (function f() {}) {
  x += typeof f;
}

x;
Copy the code

The answer to the question x is 1undefined:

  • 1
  • “1function”
  • “1undefined”
  • NaN

Heated discussion

Group friend A: Won’t the function declaration be advanced? The answer should be “1function”


Group of person B: if the condition in the judgment condition function f () {} will be converted to Boolean values, converting so true to enter the if block of code, but why typeof f is undefined?


Group friend C :(check the browser and send a picture, the result is “1function”)


Function declarations for if blocks are treated as expressions and then promoted to the top of the current scope (in this case, the global scope), i.e. :

  • function f() {}Was declared early and became the following:
var x = 1;

var f;

if ((f = function () {})) {
  x += typeof f;
}

x;
Copy the code
  • Due to the variablefIs assigned to an anonymous function that converts to a Boolean value oftrue
  • So we go intoifCode block, at this pointtypeof fAnd the result is thatfunction
  • sox += typeof fLater,xThe result should be"1function"
  • So I also think the final answer should be"1function"

After we agreed that the author of the website had got the answer wrong (the group of friends began to draw their swords to see who could pull the sword quickly and kill the author…… first)


Group friend D :(he also tested in the browser, sent a picture, the result is “1undefined”, and then silently turned to leave……)


????? What’s going on here? Does it have to do with the browser implementation?

So everyone tested the results in various browsers (maybe everyone was busy, just speaking their own ideas according to their own understanding, no one tested the results at first, I was still in bed, typing on my phone hahaha), and it was all “1undefined”.

People also began to question group C: did you declare f function before, so that the current scope already has an F function

Group friend C said: Seems to be

Solved the case, so the swords of group friends have pointed at group friend B (run away ~)


After that, we also conducted a lot of tests, had a lot of discussions and exchanged our ideas, but we still discussed around the views of the above group friends:

  • Variable declaration ahead of time
  • Anonymous function expression
  • .

Until one of my group friends (the one who shared the quiz site) posted a screenshot:

At this point, I got out of bed and turned on my computer to take the test.

  • Because this is an expression
  • The expression eventually yields a value
  • But no variable receives this value
  • This value is also destroyed after the current expression is executed
  • Therefore, subsequent read operations will find an error because it is not defined

Here, this problem is solved, we have been around the circle, is reasonable, although they say, “but where is the feeling says, persuasive enough, is mainly by the function declaration in advance to constraints, without thinking, without thinking about the nature of the problem: namely the if condition judgment condition he is actually an expression.


Expression evaluation rather than variable promotion

var x = 1;

if (function f() {}) {
  x += typeof f;
  console.log("If 里的 x:", x); // If x: 1undefined
  // console.log(" f in If: ", f); // Uncaught ReferenceError: f is not defined
}

console.log("X outside of If:", x); // If x: 1undefined
// console.log("If f: ", f); // Uncaught ReferenceError: f is not defined
Copy the code

In this piece of code, which is the original title, I’ve added a few lines of console to help:

  • In this case, the conditionfunction f() {}It’s an expression, evaluated as a function
  • However, this is an anonymous function expression, just the anonymous functionnameProperty is set tof

  • Since the result of this expression is a function, when converted to a Boolean, the converted result istrueSo I can get inifCode block (conformsB group of friendsView)
  • However, since there is no variable to receive the value (or reference/use it), the value is destroyed after the condition is executed
  • So in theifInside the code block,typeof fThe result is a string"undefined"Because there are no variables on the current scope chain at allfThe presence of
  • xAnd when you splice it together, what happens is that1undefinedthe
  • The finalconsoleAlso prints out the expected results due tofIt’s undefined, so it’s relevantfAccess comments, interested friends can copy the code to run

If we receive it with a variable, then the final value of x is what we started with 1function

var x = 1;
var f;

if ((f = function f() {})) {
  x += typeof f;
}

console.log(x); // 1function
Copy the code

Not done, we continue to dig……


Variable promotion instead of anonymous function expressions

var x = 1;

if (f) {
  function f() {}

  x += typeof f;

  // do not print, because f is undefined, if can not enter
  console.log("If 里的 x:", x);
  console.log("F" in "If ":, f);
}

console.log("X outside of If:", x); / / 1
console.log("If f:", f); // undefined
Copy the code

Here, the condition is essentially an expression, and all we need is the evaluation of that expression. But it is not the anonymous function expression evaluation mentioned above, but a normal variable evaluation:

  • inJavaScriptThe code is compiled intoASTPhase, a series of initializations are performed, includingVariable ascension(The relevant content can tell an article, interested friends can refer to information)
  • ifIn the code blockfwithdFunction declarations are captured by the compiler and promoted to the top of the scope
  • However,ifFunction declarations in code blocks, while promoting variables, are themselves treated as function expressions
if (f) {
  function f() {}}Copy the code

Equivalent to (but also related to MDN due to major browser implementations) :

var f;
if (f) {
  f = function f() {};
}
Copy the code
  • At this timefIt is defined, but its value isundefinedSo I can’t get inifBlock of code, and naturally the code inside will not execute.

The widely used IIFE

At this point, do you think of the usual immediately execute function? This is nothing more than an anonymous function expression followed by a pair of parentheses () and executed immediately.

After execution, it will be collected by GC, but we can use it to do some fun things……


conclusion

I learned a lot from this heated discussion, and I was able to prove the problem with the knowledge I learned in the past. I think it is worth recording.

There are a lot of basics to this question:

  • Variable ascension
  • The scope chain
  • Expressions are used to evaluate
  • Type judgment and type conversion
  • The difference between function expressions and function declarations
  • .

Another thing to say is:

  • Variable ascensionOccur in thecompileDuring the period of
  • Expression evaluationOccur in therunDuring the period of
  • soiftheconditionJudgment conditions (anonymous function expressions abovefunction f() {}) incompilePeriod will not beascensionBut in therunDuring the implementationevaluation(There is just no variable to receive this value.)
  • On the third point, I think we can verify it by writing anonymous function expressions in common writing:
var fn = function Foo() {};

console.log(fn.name); // Foo
console.log(Foo); // Uncaught ReferenceError: Foo is not defined
Copy the code

The group members who participated in the discussion were very active, and did not respond to some of the comments online: this question is meaningless, this question is a waste of time, who would write this kind of code?

On the contrary, I think it’s meaningful, it’s fun, it’s fun, not only to go back and uncover that mystery, but to expand your knowledge, and to incorporate what you already know.

If you have the time to express your own opinion, there is no need to pour cold water on it

But really, this kind of code is worth playing around with, and should not be used on production projects to avoid unnecessary confusion

Note: the above content combined with the discussion of group friends and personal understanding, purely personal opinion, if wrong, please point out ~


Practice is the sole criterion for testing truth!

(Finished skipping class seems to be caught by the teacher……