First of all, welcome everyone to pay attention to my Github blog, which can also be regarded as a little encouragement to me. After all, there is no way to make money by writing things, and persistence also depends on my enthusiasm and everyone’s encouragement. Readers’ Star is my motivation to move forward, please don’t be stingy with it.

The origin of

Having been writing JavaScript for two years, I thought I wouldn’t get stuck in the syntactic gutter, but I was actually slapped in the face. Recently, a handsome guy in the product development group came to me to discuss a problem. For your convenience, I have abstracted the model of this problem:

var provider = {
    test: {
        $get: function(){
            return function anonymous(config){}; }}};var type = "test";
var config = {};
new provider[type].$get()(config);
Copy the code

The above statement runs why this in anonymous refers to the window instead of the new object created by new. My first thought when I heard the question was: Nani! How is it possible that this in the constructor corresponding to the new operator does not refer to the newly created object instance? I was a little confused at the time because I hadn’t carefully abstracted the problem from the business, but when I thought about it, what was the point of this statement?

thinking

Before we say what this expression means, a few things about the new operator:

The return of the constructor

JavaScript constructors may or may not return a value, such as:

function Person(){}var person = new Person()
Copy the code

We know that the constructor returns the created instance object, the object referred to by this in the constructor. But when you have a constructor that returns a value, it’s case by case. If you return a value of a non-reference type, you are actually returning the newly created instance object. But when a value of a reference type is returned, the reference object itself is returned. Such as:

function Person(){
    return function(){}}var person = new Person()
typeof person // "function"
Copy the code

In JavaScript functions, as first-class citizens, are essentially reference types, so person is the anonymous function returned.

Two forms of the new operator

In the MDN new operator description, the syntax is

new constructor[([arguments])]

You’ll notice that ([arguments]) surrounded by brackets means default, so for constructors that don’t take arguments:

New Person() and New Person

There is no difference between the two, so let’s think about the next question, for the Person that returned the function, when

Why is new Person() executed instead of (new Person)()? For those of you who have read one of my previous articles, the new operator with arguments takes precedence over the new operator with no argument list. So the first will always be implemented rather than the second.

Now that we’ve seen the steps above, we’re getting to the heart of the problem with expressions

new provider[type].$get()(config);
Copy the code

What does the JavaScript engine parse into:

(new provider[type].$get())(config);
Copy the code

or

new (provider[type].$get())(config);
Copy the code

For the first form, (new provider[type].$get()) returns an anonymous function, so inside anonymous(config) this points to window. Provider [type].$get() returns an anonymous function, so when new Anonymous (config) is run, the internal this pointer points to the newly created instance this.

We can see from the question why this refers to the window instead of the new object created by new that the author intended to express the second meaning, but actually operates in the first way. Why is that? The reason is very simple. In the first execution method, the JavaScript engine first parses the new operator with the argument list, while in the second execution method, the function call is executed first and then the new operator is executed. As we can see from the priority graph above, the new operator with the argument list has higher priority than the function call. So it must be run the first way.

In fact, there is not much in this article, but there are two points from it. First, FROM the last article of the same kind, I emphasized to avoid the use of such vague expressions, and use a few parentheses to solve all problems. For example, some students will write something like:

var str = "Hello" + true ? "World" : "JavaScript";
Copy the code

So what does STR say? Some people might think Hello World, some people might think World, but essentially it’s World, because the + operator takes precedence over the conditional operator, so putting parentheses in there makes your code easier to read. Second, stay in awe of technology. The worst thing you can do is think you know it, but you don’t.