preface

Yesterday, I posted an article on the official account:

Don’t sell yourself short, but this one is a little hard

There was some discussion in some groups, one of which was about the arrow function’s this pointer. Ruan yifeng’s introduction to ES6 article is used to refute.

For privacy, we have blocked wechat nicknames:

ryf_group

The screenshot above is from Ruan Yifeng’s Introduction to ECMAScript 6:

this

Let’s look at what the arrow function this looks like.

A disaster caused by a problem

At first, a friend in the group asked why the two outputs were different.

What about an empty Person and a person with a value?

So let’s first analyze what’s going on.

Getval of a normal function

let pp = new person(“251”);

Here a Person instance PP is created. Then execute pp.getVal ().

Pp calls getVal, following the logic mentioned in the previous article, so getVal’s this points to the PP instance and prints out the contents of the PP instance.

No one seems to have any doubts about that. Everything is fine.

Getval of the arrow function

Similarly, let pp = new person(“251”); Here an instance of pp is created and pp.getVal () is executed.

So who does the arrow function this point to?

Don’t underestimate yourself, but this one is a little hard

Arrow function this: the current arrow function points to whoever the parent points to.

So the question is, who is the parent of the arrow function getVal?

From the perspective of lexical scope, you can see that the parent of getVal is the object O returned by the Person function, but the O object is not a function scope. There is no this context, and of course getVal cannot point to the context of the O object.

As a rule, we continue to look up this and find the Person function!

That’s it. Getval’s this refers to this of the Person function, so getVal’s this is exactly the same as the Person function this. (In fact, the arrow function’s this is a normal variable that refers to the parent’s this.)

So the question is, who does the person function’s this point to?

Let’s add a little log to enhance our understanding. The code is as follows:

var flag=996;

function person(fg){

    let o = new Object(a);

    o.flag = fg;

    o.getval=(a)= >{

        console.log(this);

    }

    this.a = 1;

    console.log("^ ^ ^ ^ ^ ^");

    console.log(this);

    console.log("^ ^ ^ ^ ^ ^");

    return o;

}

var pp = new person("251")

pp.getval();

console.log("& & & & & & &");

console.log(pp);

console.log("& & & & & & &");



// The output is as follows:

^ ^ ^ ^ ^ ^

person {a1}

^ ^ ^ ^ ^ ^

person {a1}

& & & & & & &

{flag"251".getval: ƒ}

& & & & & & &

Copy the code

Here the getVal function is the arrow function, and we know that it always corresponds to the parent person’s this, where the person’s this context is set to this.a = 1, so {a:1} is printed.

The object returned by the person function, o, is used when executing the new operator.

We then see the output pp instance, which fully outputs the contents of the returned object of the person function: {flag: “251”, getVal: ƒ}.

Here we have a question: what is the difference between this of person and this of PP instances?

The key point here is the new operator

Since the person function returns an object (other than null), the person return value o object is used in new, and the context of Person this is not returned to the instance pp.

If the person function returns a number, string, Boolean, etc., the value is ignored when new, and the context of the Person function this is returned to the instance object by default.

This is why the output pp instance does not contain this.a as defined in the person function.

The arrow function’s this points to person’s this, which prints this.a=1 but does not contain the o object returned by the person function.

Summary: the arrow function’s this always refers to the parent person’s this, not the pp instance. In fact, the arrow function’s this is like a normal variable associated with the parent function’s this

Example:

var flag=996;

function person(fg){

    let o = new Object(a);

    o.flag = fg;

    o.getval=(a)= >{

        console.log(this);

    }

    this.a = 1;

    return true;

}

var pp = new person("251");

console.log(pp.a);/ / 1

Copy the code

In the case of new person, the return value of the person function is not an object, so we ignore it.

The PP instance gets the this of the Person object.

Arrow function

Two main points:

  • In arrow functions, call and apply ignore this. (MDN description)

This is actually “representation”, in fact, because the arrow function this refers to the parent this, because the arrow function does not have this itself, so it cannot modify its this, in a word “ignore”.

  • The arrow function’s this always follows the parent’s this.

The arrow function’s this looks up this from the current arrow function, pointing to it as its own this if it finds it, and continues to look up if it doesn’t. The parent’s this is mutable, so the arrow function’s this can change with the parent.

Why do we keep following the parent this? In fact, the arrow function’s this is just like a normal variable, and the content of the variable is the parent function’s this, a variable assignment.

Therefore, this, which wants to modify the arrow function “itself”, cannot do so.

But you can change the this of the child arrow function by changing the parent’s this.

A chestnut, please

function outer(){

    var inner = function(){

        var obj = {};

        obj.getVal=(a)= >{

            console.log("* * * * * * *");

            console.log(this);

            console.log("* * * * * * *");

        }

        return obj;

    };

    return inner; 

}

outer()().getVal();

// The output is as follows

* * * * * * *

Window {parent: Window, openernull.top: Window, length0.frames: Windows,... }

* * * * * * *

Copy the code

The getVal function is the arrow function, and the this in the method follows the parent this.

After outer() executes, the closure function inner is returned

It then executes the closure function inner, whose inner is a normal function that still follows “who calls, to whom”. Instead of calling the object directly, the outermost “omitted” window is called, so the “this” of inner refers to the window.

The scope of a closure function is the same as the scope of the parent function. We can understand that the scope of a closure function has been removed from the parent function, but can also directly access the variables and parameters of the parent function.

Here inner is actually scoped the same as outer.

Change the this of the arrow function

We can use Bind to change this of the parent inner function to change this of the child arrow function getVal.

Example:

function outer(){

    var inner = function(){

        var obj = {};

        obj.getVal=(a)= >{

            console.log("* * * * * * *");

            console.log(this);

            console.log("* * * * * * *");

        }

        return obj;

    };

    return inner; 

}

outer().bind(outer)().getVal();

// The output is as follows

* * * * * * *

ƒ outer () {

    var inner = function(){

        var obj = {};

        obj.getVal=(a)= >{

            console.log("* * * * * * *");

            console.log(this);

            console.log("* * * * * * *");

        }

  …

* * * * * * *

Copy the code

Here we call outer and return inner.

Then we change inner’s this pointer, using bind to point inner’s this to outer.

As we see, the output of this is the outer function. Here we have successfully changed the this reference of getVal.

The arrow function’s this has been changed along with the parent element’s this. (Indeed, this of the arrow function is simply an assignment of the parent function context this.)

Ruan yifeng article in the arrow function description

We copied the main points of the original text as follows:

The arrow function has several uses with caution.

(1) The this object inside the function is the object at which it is defined, not the object at which it is used.

The first of these four points is particularly noteworthy. The point of this object is mutable, but in arrow functions, it is fixed.

Two core points are expressed here:

  • The this object inside the function is the object in which the definition is made

Yes, the this object in the arrow function refers, at definition, to the parent object in the lexical scope.

  • The point of this object is mutable, but in arrow functions, it is fixed

The this object of ordinary functions is specified and of course mutable. The arrow function “this” is fixed, pointing to the parent context “this”.

The conclusions are as follows:

The arrow function’s this is a normal variable that refers to the parent function’s this, and that reference never changes and cannot be changed.

However, if we need to modify this of the arrow function, we can modify this of the child arrow function by modifying the this pointer of the parent. The root cause is that the arrow function does not have this and uses the parent this at runtime.

If there are omissions, welcome to correct ~. Add my personal wechat account to communicate: lqYYgyss

Welcome to pay attention to my wechat public number, do together reliable front end!