The title

Read more excellent articles from the past to follow me
GitHubSee the oh

function Foo() { getName = function () { alert (1); }; return this; } Foo.getName = function () { alert (2); }; Foo.prototype.getName = function () { alert (3); }; var getName = function () { alert (4); }; function getName() { alert (5); } // Write the following output: foo.getName (); getName(); Foo().getName(); getName(); new Foo.getName(); new Foo().getName(); new new Foo().getName();

The classic part of this question is that it comprehensively examines the candidate’s comprehensive ability in JavaScript. Contains the variable definition ascension, this pointer, operator precedence, prototype, inheritance, global variables, pollution, object and prototype attribute knowledge such as priority, this topic on the Internet also has some relevant explanation, of course I think it is part of the explanation is inappropriate and is not clear, specially to analyze a start to end, of course we will put the final answer on the back, And to change this question a little bit more difficult, the improved version is also put in the last, convenient for the interviewer when the question has a reference.

The first question

Let’s look at what we did in the first half of the problem. First we defined a function called Foo, then we created a static property called getName for Foo to store an anonymous function, and then we created a new anonymous function called getName for the prototype object of Foo. We then create a function called getName through the function variable expression, and finally declare a function called getName.

The first question is to access the static properties stored in the Foo function, and the answer is 2. There is no need to explain too much. Generally, the first question is not necessary for students who know a little JS basic should be no problem, of course, we can use the following code to review the basic, first deepen understanding

function User(name) { var name = name; // private this.name = name; // public function getName() {// private method return Name; }} user.prototype.getName = function() {// public method return this.name; } User.name = 'Wscats'; // Static property User.getName = function() {return this.name; } var Wscat = new User('Wscats'); / / instantiate

Note the following points:

  • To call public methods and public properties, we must instantiate the object. We can instantiate methods and properties of the object by using the new operator, and public methods cannot call private methods or static methods
  • Static methods and static properties are things that we can call without instantiating
  • The object’s private methods and properties are not accessible to the outside world

The second question

Second, call the getName function directly. Since this is a direct call, it accesses a function called getName that is currently in the scope above, so we should focus on 4 and 5 directly, not on 1, 2, 3. And then of course I asked a couple of my colleagues and most of them said 5. There are actually two pits here: one is the promotion of variable declarations, and the other is the difference between function expressions and function declarations. So let’s see why, by looking at (1) function declarations and function expressions in JavaScript and (2) variable promotion in JavaScript, there are two types of defining functions in JavaScript, right

Function declaration

Function wscat(type) {return type === "wscat"; }

Functional expression

Var oaoafly = function(type) {return type === "oaoafly"; }

Let’s start with the classic problem of defining a function named getName using both a function declaration and a function expression in a program

getName() //oaoafly
var getName = function() {
    console.log('wscat')
}
getName() //wscat
function getName() {
    console.log('oaoafly')
}
getName() //wscat

The code above looks similar and doesn’t feel much different. But in fact, one of the “pitfalls” of JavaScript functions is that there are two types of function definitions in JavaScript.

  • There is a mechanism in the JavaScript interpreter for variable declarations to be promoted, which means that function declarations will be promoted to the front of the scope, even if they are written at the end of the code.
  • A function created with a function expression is assigned at run time and cannot be called until the expression assignment is complete
Var getName // variable is promoted, in this case it is undefined getName() // OAOAFLY function is promoted, which is affected by function declaration. Var getName = function() {console.log('wscat')} var getName = function() {console.log('wscat') GetName () {console.log('oaoafly')} getName() //wscat executes the function expression value

So you can break it down into these two simple questions and see the nature of the difference

var getName;
console.log(getName) //undefined
getName() //Uncaught TypeError: getName is not a function
var getName = function() {
    console.log('wscat')
}            
var getName;
console.log(getName) //function getName() {console.log('oaoafly')}
getName() //oaoafly
function getName() {
    console.log('oaoafly')
}

This distinction may seem trivial, but in some cases it can be a subtle and deadly trap. The essence of this pitfall is the difference between the two types in function promotion and runtime (parse time/runtime). There is a difference between a function declaration and a function expression in JavaScript. A function declaration promotes a function at JS parsing time, so that the function can be called within the same scope no matter where the function declaration is defined. The value of a function expression is determined at JS runtime, and the function cannot be called until the expression is assigned. So the answer to the second question is that the function declaration for 4 and 5 is overwritten by the function expression for 4

The third question

Foo().getName(); The Foo function is executed, and then the getName property function of the return value object of the Foo function is called. Function () {alert (1); function () {alert (1); }; GetName = “Foo”; getName = “Foo”; getName = “Foo” Function (){alert(1)} function(){alert(1)} function(){alert(1)} function(){alert(1)} This is actually changing the getName function in the outer scope.

Note: If it is still not found, it will look up to the window object. If there is no getName property in the window object, it will create a getName variable in the window object.

After that, the return value of Foo is this, which has been covered in many articles, so I won’t talk about it here. Simply put, the direction to this is determined by how the function is called. In this case, this refers to the window object. The Foo function returns the window object, which is equivalent to doing window.getName(). The getName in the window has been changed to alert(1), so it will print 1. One is the “this” problem and we can review both of these points with the following code

var name = "Wscats"; // global variable window.name = "Wscats"; // function getName() {name = "Oaoafly"; Var privateName = "Stacsw"; var privateName = "Stacsw"; return function() { console.log(this); //window return privateName } } var getPrivate = getName("Hello"); // OAOAFLY console.log(getPrivate()) //Stacsw (); // OAOAFLY console.log(); // OAOAFLY console.log()

Because no block-level JS scope, but the function is to produce a scope, function value within the different definitions of methods will directly or indirectly affect the global or local variables and function within the private variables can use closures, function also is really the first citizen ah ~ on this, this point in a function definition cannot be determined, It’s only when the function is executed that we know who this refers to. In fact, this ultimately refers to the object that called it. So in the third question, it’s actually window calling Foo(), so this refers to window

window.Foo().getName();
//->window.getName();

The fourth question

}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} So the result is that Foo() executes the overridden getName function

5 q

New foo.getName (); Here we examine the priority of JS operators, and I think this is the heart of the problem, and it is also a difficult problem. Here is the priority table of JS operators, ranked from highest to lowest. Refer to the MDN operator precedence

priority Operation type Correlation between The operator
19 parentheses n/a (…).
18 Member access From left to right … ….
Member accesses to be computed From left to right … […].
New (with argument list) n/a new … (…).
17 A function call From left to right … (…).
New (no argument list) From right to left The new…
16 Postincrement (operator after) n/a … ++
Post decrement (operator after) n/a … —
15 Logic is not From right to left ! …
According to a non From right to left ~…
One yuan addition From right to left +…
One yuan subtraction From right to left -…
Increasing pre – From right to left + +…
Front of diminishing From right to left -…
typeof From right to left Typeof…
void From right to left Void…
delete From right to left The delete…
14 The multiplication From left to right … *…
division From left to right … /…
modulus From left to right … %…
13 add From left to right … +…
subtraction From left to right … -…
12 According to a shift to the left From left to right … < <…
According to the position moves to the right From left to right … > >…
Unsigned to the right From left to right … > > >…
11 Less than From left to right … <…
Less than or equal to From left to right … < =…
Is greater than From left to right … >…
Greater than or equal to From left to right … > =…
in From left to right … The in…
instanceof From left to right … Instanceof…
10 The equal sign From left to right … = =…
The equal sign From left to right … ! =…
All the equals sign From left to right … = = =…
Not all equal From left to right … ! = =…
9 Bitwise and From left to right … &…
8 The bitwise exclusive or From left to right … ^…
7 Bitwise or From left to right … Bitwise or…
6 Logic and From left to right … &&…
5 Logic or From left to right … Logic or…
4 Conditional operator From right to left … ? … :…
3 The assignment From right to left … =…
… + =…
… – =…
… * =…
… / =…
… % =…
… < < =…
… > > =…
… > > > =…
… & =…
… ^ =…
… Or =…
2 yield From right to left Yield…
yield* From right to left Yield *…
1 Expansion operator n/a . …
0 The comma From left to right … ,…

New is higher than new, higher than function calls, and the same level of priority as member access

new Foo.getName(); The priority of the

It is equivalent to:

new (Foo.getName)();
  • The point has a higher priority (18) than the new no-argument list (17)
  • And then when the dot is done because there’s a parenthesis(a), is a new argument list (18), so the direct execution of new, may also have friends, of course, there will be a question why don’t have () function call new again, that’s because the function call (17) than new argument list (18) low priority

.member access (18)->new has parameter list (18)

So the getName function is actually executed as a constructor, and 2 pops up.

Q 6

The only difference between this one and the last one is that there’s an extra parenthesis in Foo, and this one with parentheses or without parentheses we saw in question 5 that there was a difference in precedence

(new Foo()).getName()

So how do we judge that here? First of all, new has the argument list (18) at the same level as the priority of the point (18), and then the priority of the point (18), and finally the function call (17).

New has parameter list (18)->. Member access (18)->() function call (17)

There is also a small point here, Foo as a constructor has a return value, so here we need to explain the JS constructor return value problem.

The return value of the constructor

In traditional languages, a constructor should not have a return value; the actual return value executed is the instantiated object of the constructor. In JS, constructors may or may not return a value.

  1. If no value is returned, the instantiated object is returned as in any other language.

    function Foo(name) {
     this.name = name
    }
    console.log(new Foo('wscats'))

  2. If there is a return value, check whether it is a reference type. If is a reference type, such as basic types (String, Number, Boolean, Null, and Undefined) with no return values are the same, the actual return to instantiate the object.

    function Foo(name) {
     this.name = name
     return 520
    }
    console.log(new Foo('wscats'))

  3. If the return value is a reference type, the actual return value is that reference type.
function Foo(name) {
    this.name = name
    return {
        age: 16
    }
}
console.log(new Foo('wscats'))



In the original case, Foo returns the instantiated object because it returns this, which in the constructor already represents the current instantiated object.

The getName function for the instantiated object is then called. Since no properties have been added to the instantiated object in the Foo constructor, look for the getName function in the prototype object for the current object.

As a side note, if the constructor and the stereotype chain have the same method, as shown in the following code, then the default method will be the constructor’s public method instead of the stereotype chain. This was not shown in the original problem, but I have added it in an improved version.

function Foo(name) {
    this.name = name
    this.getName = function() {
        return this.name
    }
}
Foo.prototype.name = 'Oaoafly';
Foo.prototype.getName = function() {
    return 'Oaoafly'
}
console.log((new Foo('Wscats')).name) //Wscats
console.log((new Foo('Wscats')).getName()) //Wscats

7 q

new new Foo().getName(); It’s also an operator precedence issue. I don’t think the answer is that important anymore. It’s just that the interviewer really knows what they’re looking at us for. The final actual implementation is as follows:

new ((new Foo()).getName)();

New has parameter list (18)->new has parameter list (18)

The instantiation object of Foo is initialized, and then the getName function on its prototype is used as the constructor again, so the final result is 3

The answer

function Foo() { getName = function () { alert (1); }; return this; } Foo.getName = function () { alert (2); }; Foo.prototype.getName = function () { alert (3); }; var getName = function () { alert (4); }; function getName() { alert (5); } // Answer: foo.getName (); //2 getName(); //4 Foo().getName(); //1 getName(); //1 new Foo.getName(); //2 new Foo().getName(); //3 new new Foo().getName(); / / 3

subsequent

Subsequent I increase the difficulty of this problem again slightly a little (with answers), add a public method in function Foo getName, for the following questions if used on the interview questions that pass rate may be lower, because the difficulty is a bit big, two more pit, but understand this principle is equivalent to understand all the above

function Foo() { this.getName = function() { console.log(3); Return {getName: getName // This is the return value of the constructor in the sixth question}}; GetName = function() {console.log(1); getName = function() {console.log(1); }; return this } Foo.getName = function() { console.log(2); }; Foo.prototype.getName = function() { console.log(6); }; var getName = function() { console.log(4); }; function getName() { console.log(5); } // Answer: foo.getName (); //2 getName(); //4 console.log(Foo()) Foo().getName(); //1 getName(); //1 new Foo.getName(); //2 new Foo().getName(); New Foo().getName().getName().getName(); //3 1 new new Foo().getName(); / / 3

Finally, actually I’m not putting these questions as the only evaluation to examine the interviewer, but as we should not be a qualified front end engineers because impetuous ignores some of our most basic knowledge, of course, I also wish all the interviewer find a ideal job, wish all the interviewer find that horse ~ in my heart

communication

If articles and notes give you some help and inspiration, please don’t stingy your praise and collection, the article synchronous update continuously, can WeChat search “front-end roam” pay attention to the public, it’s convenient, you read back the articles included in https://github.com/Wscats/art… Welcome your attention and communication, your affirmation is the biggest power for me to move forward?