The first question

    // Declare a function Foo
    function Foo () {
        getName = function () { console.log(1); }return this;
    }
    Foo creates a static property called getName to store an anonymous function
    Foo.getName = function () { console.log(2); };
    // Foo's prototype object creates an anonymous function called getName
    Foo.prototype.getName = function () { console.log(3); };
    // Declare an anonymous name and assign it to the global variable getName (function expression)
    var getName = function () { console.log(4); };
    // Declare a global function getName.
    function getName () { console.log(5); }

    Foo.getName(); / / the first question
    getName(); / / the second asked
    Foo().getName(); / / the third asked
    getName(); / / q 4
    new Foo.getName(); / / q 5
    new Foo().getName(); / / 6 q
    new new Foo().getName(); / / q 7
Copy the code

If these questions can be answered directly, there is no need to read later.

A quick look at prototype inheritance in javascript

    function Preson(name) {
        var name = name; // Private attributes
        this.name = name; // Public attributes
        function getName() { // Private methods
            return name;
        }
    }
    Preson.prototype.getName = function() { // Public method
        return this.name;
    }
    Preson.name = 'Wscats'; // Static attributes
    Preson.getName = function() { // Static method
        return this.name;
    }
    var Son = new Preson('Son'); / / instantiate
Copy the code

Note the following points:

  • To call public methods, public properties, we must first instantiate the object, that is, to implement the object with the new operator, the constructor can instantiate the object’s methods and properties, and the public method is not able to call private methods and static methods
  • Static methods and static properties are called without instantiation
  • The private methods and properties of objects are not externally accessible
  • Static properties cannot be inherited

First look at the code, as follows:

    function Foo () {}
    Foo.getName = function () { console.log(2); }
    Foo.prototype.getName = function () { console.log(3); };
Copy the code

First look at the Foo. GetName in Foo. Prototype. Add a getName attribute constructor, if direct call Foo getName he direct call Foo prototype. GetName attribute on the constructor. The getName property in Prototype cannot be accessed without calling Foo with the new keyword. The code results are as follows:

The first question

    Foo.getName(); / / the first question
    / / 2
Copy the code

GetName (Foo. Constructor) ¶ Foo. GetName (Foo. GetName) calls the static attribute from constructor, resulting in 2.

The second question

    getName(); / / the second asked
    / / 4
Copy the code

Function declarations and function expressions are introduced as follows:

Function declaration

    // Function declaration
    function getName () {}
Copy the code

Functional expression

    // Function expression
    var getName = function () {}
Copy the code

Variable promotion is a function declaration that has variable promotion. If you don’t know about variable promotion, you can read another article about variable promotion in javascript, so the answer to this question is 4.

The third question

    Foo().getName(); / / the third asked
    / / 1
Copy the code

Foo().getName(); Function Foo is executed, and then the getName property function of the return value object of function Foo is called. We mainly examine the this pointing problem and the problem of declaring variables in Foo without var. Note that the getName declaration in Foo does not have var, so it creates a getName in the global scope. If this property exists in the global scope, it overrides the existing properties in the global scope. So when Foo is done getName = function () {console.log(1); } will override getName = function () {console.log(4); }.

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

Foo returns this, and JS’s this problem has been discussed in many articles. Simply speaking, the direction of this is determined by how the function is called. So the answer is output 1. Here is the main investigation of two knowledge points, one is the scope problem, one is this pointing to the problem, this will not do more to explain directly to the next article.

The fourth question

    getName(); / / q 4
    / / 1
Copy the code

Call getName directly, equivalent to window.getName(), because this variable has been modified by Foo, and the result is the same as the third question, which also prints 1.

5 q

    new Foo.getName(); / / q 5
    / / 2
Copy the code

The fifth question mainly inspects the operator priority in JS, so it is necessary to first understand the operator priority in JS, which can be learned through MDN operator priority here is not shown, only used as shown in the following figure:

Two points can be seen above:

  • Member access.Priority of **(19)There is no parameter list than new(18)** has high priority
  • And then when the dot is done and there’s a parenthesis (), it becomes new and there’s a list of arguments **(19)., so just execute new,new constructorYou can followA class or function that specifies the type of an instance of an object. It is theFoo.getName()As aAs a wholeInstead of calling upnewAfter donefunctionIt works if you don’t believe itnew (Foo.getName)The code, the result of that and the problemThe result is consistent. So we can rewrite the code asnew (Foo.getName)()In this way, the execution sequence can be clearly seen. The major execution sequence is divided into two steps as follows:
  1. To perform firstFoo.getName
  2. Then thenew (Foo.getName)()

So the getName function is actually executed as a constructor, so the result is 2.

Q 6

    new Foo().getName(); / / 6 q
    / / 3
Copy the code

New has the argument list (19) and the priority of the point (19), which are executed from left to right. Therefore, new has the argument list (19) first, then the priority of the point (19), and finally the function call (18).

New has the argument list (19)->. Member access (19)->() function call (18). The above question should be written as (new Foo()).getName(), depending on the priority, so that you can see it more clearly.

The return value of the constructor

In traditional languages constructors should not have a return value, and the actual return value executed is the constructor’s instantiation object, whereas in JS constructors may or may not have a return value. It can be roughly divided into three categories:

  • If no value is returned, the instantiated object is returned as in any other language.
  • If there is a return value, check whether the return value 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.
  • If the return value is a reference type, the actual return value is that reference type.

In the original problem, Foo returns the instantiated object because it returns this, which in the constructor represents the currently instantiated object. We then call the getName function of the instantiated object, because we didn’t add any properties to the instantiated object in the Foo constructor and look for getName in the prototype of the current object. Function () {alert (3); function () {alert (3); }; , the result is 3.

7 q

    new new Foo().getName(); / / q 7
    / / 3
Copy the code

Question 7 can be rewritten to new ((new Foo()).getName)() according to the priority of question 6, so the result is also 3.

conclusion

In fact, there are a lot of this reference, constructor return value, scope are not fully documented, some of the previous articles but not sorted out, slowly will be sorted out.