Three questions of life: Who am I? Where am I from? Where am I going? In philosophy, no one can really answer these three questions, in the same way, in js, because things too much, to really understand what this represents in various circumstances js is a difficult thing, even more embarrassed, this the key word, in the js is not only complicated but also use a lot of, so don’t understand what this represents, Don’t dare to write JS, let alone look at other people’s code, more laborious.

This always points to the object on which the function was run, not the object on which the function was created, and this is the object on which the function was last called, except for arrow functions and functions bound to bind. This four binding rule: the default binding, explicitly bound, implicit binding, new binding, as already said this is not only complicated but also very important, but don’t be afraid, as long as understand the display binding, basic can control this, of course is based on a large number of practice under the premise of, because of the implicit binding and is derived from the explicit binding to the default binding, The following is a combination of various situations to analyze the direction of this.

Call, apply, and this(explicit binding)

In JS, functions are also objects, so there are methods. Call and apply are methods of functions. You can explicitly specify the object to which this of a function points, i.e. the first parameter of call and apply.

function foo() {
    console.log( this.name);
} 
 
var obj = {
    name: 'Ming'
}; 
 
foo.call(obj); / / = > xiao Ming
foo.apply(obj); / / = > xiao Ming

var tmp = foo.bind(obj)
tmp() / / = > xiao Ming
Copy the code

Bind and this (explicit, hard)

Bind is similar to call and apply, except that it executes immediately, whereas bind returns a function that is always bound to an object. Bind sets the function’s this value regardless of how the function was called. Calling f.bind(someObject) creates a function with the same body and scope as f, but in this new function, this is permanently bound to the first argument of bind, regardless of how the function is called.

function foo() {
    return this.a;
}
var bar = foo.bind({
    a: 'hello'
});
console.log(bar()) // hello
var o = {
    a: 'world'.foo: foo,
    bar: bar
};
console.log(o.foo(), o.bar()) // world hello

Copy the code

Global this(default binding)

function foo() {
    console.log( this);
} 
foo();//window
Copy the code

The above code can be read as foo.call(window) in explicit binding terms.

With this new

function Person(n, a, g){
  this.name = n;
  this.age = a;
  this.gender = g;
  console.log(this);
}
// as a constructor
var o = new Person("Lily".18."F"); // This is the current object Person {name: "Lily", age: 18, gender: "F"}

Copy the code

A constructor differs from a normal function in that it is called rather than defined. Using the new keyword is a constructor; otherwise, it is a normal function. The new keyword changes the reference of this within the function to the newly created object.

Cannot return an empty object.

    function Person(n, a, g){
        this.name = n;
        this.age = a;
        this.gender = g;
        return {};// Returns an empty object
    }
    // as a constructor
    var o = new Person("Lily".18."F");
    console.log(o.name) //undefined
Copy the code

But you can return basic data questions.

    function Person(n, a, g){
        this.name = n;
        this.age = a;
        this.gender = g;
        return 1;  // Returns the scalar
    }
    // as a constructor
    var o = new Person("Lily".18."F");
    console.log(o.name) //Lily
Copy the code

This (implicit binding) as an object method

let name = 'global';
var obj = {
    name: 'Ming'.getName: function () {
        return this.name; }};// called as an object method
console.log(obj.getName());   / / xiao Ming
Copy the code

To understand this explicitly, the above code can be read as obj.getName.call(obj). This refers to the last object to call the function, not the first object

var parent = {
    age:30.son: {age:5.getAge:function(){
            console.log(this.age); //5, will print the son's age instead of the parent's age
        }
    }
}
parent.son.getAge();
Copy the code

Object method called as function this(default binding)

window.age = 100;

var obj = {
    age: 10.getAge: function () {
        return this.age; }};var getAge = obj.getAge;
// called as a normal function
console.log(getAge());   / / 100

Copy the code

Although the getAge method is an obj object, the object that ultimately calls the method is the window, which can be interpreted as getAge. Call (window)

This on the object prototype chain

function Foo(){
    this.x = 10;
}
Foo.prototype.getX = function () {
    console.log(this);        //Foo {x: 10, getX: function}
    console.log(this.x);      / / 10
}
var foo = new Foo();
foo.getX();
Copy the code

In foo.prototype. getX, this points to Foo. Not only that, but even throughout the prototype chain, this represents the value of the current object.

This in the Es6 arrow function

The arrow function is not only a shorthand for anonymous functions, but also a better way to encapsulate callback functions by solving the this pointing problem of anonymous functions. The this object in the body of the arrow function is referred to by the scope in which the function was defined, not by the scope in which it was used. To understand how to define an object in the scope of a function, look at the following code:

var name = 'window'; 

var A = {
   name: 'A'.sayHello: () = > {
      console.log(this.name)
   }
}

A.sayHello();// Instead of output A, output window
Copy the code

Scope is the inside of a function, so the arrow function here, sayHello, is in the scope of the outermost JS environment, because there are no other functions wrapped around it; Then the outermost JS environment points to a WinodW object, so this refers to a Window object. If we want this to point to object A, we need to wrap A function around the arrow function

var name = 'window'; 

var A = {
   name: 'A'.sayHello: function(){
      var s = () = > console.log(this.name)
      return s// return arrow function s}}var sayHello = A.sayHello();
sayHello();/ / output A
Copy the code

The logic is that sayHello is A function so the arrow function s has scope sayHello, and sayHello points to object A, so the arrow function this points to object A.

Due to the error handling of this binding by JavaScript functions, the following code does not get the expected result. This in fn will point to window or undefined and needs to be fixed with the hack method var that = this.

var obj = {
    birth: 1990.getAge: function () {
        var b = this.birth; / / 1990
        var fn = function () {
            return new Date().getFullYear() - this.birth; // This refers to window or undefined
        };
        returnfn(); }};Copy the code

But the arrow function completely fixes the pointing of this, which always points to the lexical scope, the outer caller obj:

var obj = {
    birth: 1990.getAge: function () {
        var b = this.birth; / / 1990
        var fn = () = > new Date().getFullYear() - this.birth; // This points to the obj object
        returnfn(); }}; obj.getAge();/ / 25
Copy the code

Because this is already scoped in the arrow function, the arrow function does not change this, only its defined position. Therefore, when the arrow function is called with call() or apply(), this cannot be bound, i.e. the first argument passed in is ignored.

var obj = {
    birth: 1990.getAge: function (year) {
        var b = this.birth; / / 1990
        var fn = (y) = > y - this.birth; // This. Birth is still 1990
        return fn.call({birth:2000}, year);// The first argument to the call method is ignored}}; obj.getAge(2015); / / 25

Copy the code

The DOM event is bound to this

When the function is used as an event handler, its this points to the element that triggered the event click me! btn1 click me! btn2

The this of the inline event points to the window

<button id='btn1' onclick="clickHandler()">click me! btn1</button>
<button id='btn2' onclick="clickHandler()">click me! btn2</button>
<script>
function clickHandler() {
	console.log(this.this.id)
}
</script>
Copy the code

If we want this to refer to the element in the inline event handler, we can use bind to specify its this value.

<button id='btn1' onclick="clickHandler.bind(this)()">click me! btn1</button>
<button id='btn1' onclick="clickHandler.call(this)">click me! btn1</button>
<button id='btn1' onclick="clickHandler.apply(this)">click me! btn1</button>

Copy the code

Window timer and this

Since the setTimeout() call runs on a completely separate execution environment from the function in which it is called. This causes the code to include the this keyword pointing to the Window (or global) object.

var num = 0;
function Obj (){
    this.num = 1.this.getNum = function(){
        console.log(this.num);
    },
    this.getNumLater = function(){
        setTimeout(function(){
        console.log(this.num);
        }, 1000)}}var obj = new Obj; 
obj.getNum();//1 prints obj.num with a value of 1
obj.getNumLater()//0 expects to print the num of obj, and then prints the num of window. This refers to window
Copy the code

If I want this in the timer to point to Obj,

var num = 0;
function Obj (){
    this.num = 1.this.getNum = function(){
        console.log(this.num);
    },
    this.getNumLater = function(){
        setTimeout(function(){
        console.log(this.num);
        }.bind(this), 1000)// Bind this to the function with bind()}}var obj = new Obj; 
obj.getNum();//1 prints obj.num with a value of 1
obj.getNumLater()//1 prints obj.num with a value of 1
Copy the code

Or use the arrow function to correct the pointing of this

var num = 0;
function Obj (){
    this.num = 1.this.getNum = function(){
        console.log(this.num);
    },
    this.getNumLater = function(){
            setTimeout(() = > {console.log(this.num); },1000)}}var obj = new Obj; 
obj.getNum();//1 prints obj.num with a value of 1
obj.getNumLater()//0 Prints window.num with a value of 0
Copy the code

And with this

The with statement specifies the default object for one or a group of statements. With the with statement, the code becomes shorter and more readable. If you use this in the with block, it represents the object specified by the with statement. However, because with reduces the efficiency of the code, it is not recommended in actual development and will not be discussed in detail.

This in strict mode

Strict mode doesn’t make this any more complicated. Strict mode only affects the default value of the context, that’s all.

[] and this, confused []

function fn (){ console.log(this)}var arr = [fn, fn2]
arr[0] ()Copy the code

This code makes it easy to read arr0 as fn(), which leads to the misconception that the execution is fn.call(window), which leads to the misconception that this points to window, and then the actual execution is arr0 => arr.fn() => this points to ARr.

This always refers to the object on which the function was run, not the object on which the function was created, and this is the object on which the function was last called, except for arrow and bind functions: Whether the function is called in new (new binding), and if so, this is bound to the newly created object. 2. Whether the function is called by call,apply, or bind. If so, this binds to the specified object. 3. Whether the function is called in a context object (implicitly bound), and if so, this binds to that context object. It is usually obj.foo(). 4. If none of the above, use the default binding. If in strict mode, it is bound to undefined, otherwise to a global object. 5. If Null or undefined is passed to call, apply, or bind as a binding object for this, these values will be ignored during the call, and the default binding rules will actually apply. 6. If it is an arrow function, the arrow function’s this inherits the outer code block’s this.

Refer to the article

Arrow function JavaScript this fully parses JavaScript – this