Variable declaration elevation, prototype. The question of this pointer is as follows:
Function Foo () {getName = function () {console. log (1) ;}; return this ;}foo. getName = function () {console. log (2) ;}; Foo. prototype. getName = function () {console. log (3) ;}; var getName = function () {console. log (4) ;}; function getName () {console. log (5);} // write the following output: Foo. getName (); Foo (). getName (); new Foo. getName (); new Foo (). getName (); new Foo (). getName ();
The answer is:
Function Foo () {getName = function () {console. log (1) ;}; return this ;}foo. getName = function () {console. log (2) ;}; Foo. prototype. getName = function () {console. log (3) ;}; var getName = function () {console. log (4) ;}; function getName () {console. log (5) ;}// answer: Foo. getName (); // 2 getName (); // 4Foo (). getName (); // 1 getName (); // 1new Foo. getName (); // 2new Foo (). getName (); // 3new new Foo (). getName (); // 3
This topic involves many knowledge points, including variable declaration elevation, this pointer pointing, operator priority, prototype, inheritance, global variable contamination, object attribute and prototype attribute priority, etc.
This question contains seven small questions, respectively.
Question 1
First, we define a function named Foo, and then create a static property named getName For Foo to store an anonymous function, then, an anonymous function named getName is created for the prototype object of Foo. Then, a function named getName is created through the function variable expression, and a function named getName is declared.
In the first question, Foo. getName naturally accesses the static attribute stored on the Foo function. Naturally, it is 2 and there is nothing to say.
Question 2
Second, call the getName function directly. Since it is called directly, it is to access the current getName function in the scope above, so it has nothing to do with 1 2 3. There are two pitfalls: Variable declaration escalation and function expression.
Variable declaration escalation
That is, all declared variables or declared functions are promoted to the top of the current function.
For example, the following code:
console.log(‘x’ in window);//truevar x;
x = 0;
When the code is executed, the js engine promotes the declaration statement to the top of the code and changes it:
var x;console.log(‘x’ in window);//truex = 0;
Function expression
Both var getName and function getName are declaration statements. The difference is that var getName is a function expression, while function getName is a function declaration.
The biggest problem with function expressions is that js splits the code into two lines for separate execution.
For example, the following code:
Console. log (x); // output: function x () {} var x = 1; function x (){}
The actual code is to split var x = 1 into var x; and x = 1; and then convert var x; and function x () {} two rows are upgraded to the top:
var x;function x(){}console.log(x);x=1;
Therefore, the final function declared x overwrites the variable declared x, and the log output is the x function.
Similarly, the code in the original question is:
Function Foo () {getName = function () {console. log (1) ;}; return this ;}var getName; // only variable declaration function getName () {console. log (5);} // raise the function declaration to overwrite the var declaration Foo. getName = function () {console. log (2) ;}; Foo. prototype. getName = function () {console. log (3) ;}; getName = function () {console. log (4) ;}; // The final assignment overwrites the function getName declaration getName (); // The final output 4
Third question
In the third question, Foo (). getName (); First executes the Foo function, and then calls the getName attribute function of the returned object of the Foo function.
GetName = function () {console. log (1) ;}; is a function value assignment statement. Note that it does not have a var declaration. Therefore, first look for the getName variable in the current Foo function scope, no. Search for whether the getName variable is contained in the upper-level function scope, that is, the alert (4) function in the second question, assign the value of this variable to function () {alert (1 )}.
The getName function in the outer scope is modified.
NOTE: If it is still not found, the window object will be searched up. If there is no getName attribute in the window object, a getName variable will be created in the window object.
The Return Value of the Foo function is this, and many articles have been introduced in the blog about this in JS.
In short, the point of this is determined by the method in which the function is called. The direct call method here points to the window object.
Then the Foo function returns the window object, which is equivalent to executing window. getName (), while the getName in the window has been changed to alert (1), so it will output 1
Two knowledge points are discussed here. One is the scope of variables, and the other is the this point.
Fourth Question
Directly call the getName function, which is equivalent to window. getName (). Because the variable has been modified when the Foo function is executed, the result is the same as that of the third question, which is 1.
Fifth Question
The fifth question is "new Foo. getName ();". Here we examine the operator priority of JavaScript.
Js operator priority:
Reference: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Operator_Precedence
By checking the table above, we can know that the priority of vertex. is higher than that of the new operation, so it is equivalent:
new (Foo.getName)();
Therefore, the getName function is actually executed as the constructor. Then, 2 is displayed.
Question 6
The sixth question is "new Foo (). getName ()". First, we can see that the operator priority () is higher than "new", and the actual execution is
(new Foo()).getName()
Then execute the Foo function first, while Foo has returned values as the constructor at this time. Therefore, we need to describe the constructor return values in js.
Return Value of the constructor
In traditional languages, constructor should not return values. The actual returned values are the instantiated objects of the constructor.
In js, constructor can return values or not.
1. If no value is returned, the instantiated object is returned in the same way as other languages.
function F(){}new F()//>F {}
2. If a return value exists, check whether the return value is of the reference type. If it is a non-reference type, for example, the basic type (string, number, boolean, null, undefined) is the same as the non-return value, the actual returned instantiated object is returned.
function F(){return 1;}new F()//>F {}
In the original question, this is returned, and this originally represents the current instantiated object in the constructor, then the final Foo function returns the instantiated object.
Then, call the getName function of the instantiated object. Because no attribute is added to the Foo constructor, The getName is found in the prototype of the current object.
Finally, output 3.
Question 7
Question 7: new Foo (). getName (); is also an operator priority.
The actual execution is:
new ((new Foo()).getName)();
Initialize the instantiated object of Foo and use the getName function on its prototype as the constructor to create a new object.
The final result is 3.