“This is the third day of my participation in the November Gwen Challenge. See details of the event: The last Gwen Challenge 2021”.

preface

This question was invented by Ali a few years ago and has caused job interview disaster. You may be able to say the result, but you may not be able to say the cause.

I looked up part of the explanation of this question, and many of them just finished in a daze, not grasping the core of the problem at all. Therefore, Ah Bao also offered his own understanding, hoping to add a vote for the right side, so that people can search for the right side more frequently.

Here is the original Ali question and explanation:

Portal: Ali subject link

The title

function test() {           
    getName = function() { 
        Promise.resolve().then(() = > console.log(0)); 
        console.log(1);               
    };

    return this; 
}
test.getName = function() { 
     setTimeout(() = > console.log(2), 0); 
     console.log(3);               
};
test.prototype.getName = function() {    
     console.log(4); 
};       
var getName = function() { 
     console.log(5);             
};
function getName() {
     console.log(6); 
}      
      
test.getName(); 
getName(); 
test().getName(); 
getName();  
new test.getName();
new test().getName();
new new test().getName();
Copy the code

Analysis of the

This topic covers a lot of topics, such as scopes, precompilation, prototypes and prototype chains, new, and event loops.

Let’s first analyze what the first half of the problem actually does:

  1. definetestfunction
  2. fortestThe function creates a static methodtest.getName
  3. fortestThe function creates an instance methodtest.prototype.getName
  4. Defining global variablesgetNameAfter the program runs, it is assigned to a function
  5. Defining global functionsgetName
  6. testFunction internals to global variablesgetNameAssigns a new value and returns a value ofthis

Compared with the original topic, the current topic adds the knowledge of event loop, Promise. Then and setTimeout are both asynchronous tasks, the former is a micro task, the latter is a macro task.

parsing

precompiled

  1. Function precompiled tetralogy and global precompiled trilogy
  2. Variable declaration, declaration promotion, function declaration, overall promotion
GO: {
    test: fn,
    
    getName: function getName() { console.log(6); }}Copy the code

test.getName()

Execute the static method test.getName on the test function, print 3, and the setTimeout callback is inserted into the event queue, waiting for the synchronization task to complete

getName()

Before getName executes, getName has been reassigned to console.log(5), printing 5

test().getName()

  1. test()Execute globallytestFunction to modify the globalgetNameValue;test()Functions are executed in default binding, non-strict modethisPoint to thewindow, the return value iswindow
GO: {
    test: fn,
    // Change the global getName value
    getName: function() { 
        Promise.resolve().then(() = > console.log(0))
        console.log(1);               
    };
}
Copy the code
  1. test().getName()Equivalent to carrying outwindow.getName(), the callGOIn thegetNamePromise.thenPress into the microtask queue and print1

getName()

Execute the global function getName(), printing 1, promise.then to press the microtask queue

(⭐) New knowledge supplement

Let’s add a little bit of knowledge about the new operator before we go through the rest of the problem.

First let’s look at the description of new in MDN. The syntax is:

    new constructor[([arguments])]
Copy the code

([arguments]) means that by default, new constructor(… Args) and New constructor, and the former takes precedence over the latter. More detailed priorities are shown below:

As you can see from the figure above, some of the priorities are as follows:New (with argument list) = Member access = function call > new(without argument list)

new test.getName()

From left to right, there are three operators: new with no argument list, member access, and function call.

Operators of the same priority are executed from left to right, so member access is performed first to get the static method getName on the test function.

After member access, the expression changes to new (test.getName)(), the new operator changes from no argument list to argument list, executes from left to right, treats test.getName as a constructor, and generates the corresponding instance.

New (test.getName)() executes, prints 3, setTimeout callback presses into the macro task queue.

new test().getName()

The expression operators from left to right are: new with argument list, member access, function call

  1. performnew test(): newBinding,thisPoint to an instance.
  2. newNot on the build instancegetNameProperty, found along the prototype chaintest.prototype.getNameProperties, print4

new new test().getName()

Expression operators from left to right are: new with no arguments, new with arguments, member access, function call

So the expression can be converted to the form: new((new test()).getName())

  1. new test().getName: access to thetest.prototype.getNameattribute
  2. new new test().getName()To:test.prototype.getNameFor the constructor, print4

Promise.then

Execute the promise.then in the microtask queue, there are two promises. then, and print two zeros

setTimeout

Execute the setTimeout callback in the macro task queue, printing two 2s

The answer

3
5
1
1
3
4
4
0
0
2
2
Copy the code

Past wonderful articles

  • Cow guest latest front-end JS written test 100 questions
  • Grab the latest front end test five hundred data analysis JS interview hot spots
  • Native JavaScript soul torture (2), can you answer all correctly?
  • Native JavaScript soul Test (1), how much can you answer?
  • A thorough understanding of prototypes and prototype chains in JavaScript
  • JavaScript precompilation learning
  • Complete understanding of EventLoop in JavaScript
  • “2W word big chapter 38 interview questions” completely clear JS this pointing to the problem

After the language

If you feel that this article is of some help to you, I hope you can give a thumbs-up to encourage Bao, Bao will continue to work hard. In addition, if this article has a question, or do not understand part of the article, you can reply to me in the comment section, we come to discuss, learn together, progress together!

If you feel confused in the comments section, you can also add my wechat or QQ for detailed communication, and the name is battlefield small bag.