1. What is this

In JS, there is an amazing this mechanism

Let’s start with an example:

var person = {
    namer: 'Joe'.sayNmae: function() {
        console.log(namer); }}var namer = 'bill'
person.sayNmae();  / / li si
Copy the code

Oh, my God. What’s wrong with what we thought?

This is because the variables in the sayNmae method are under the global scope, but we want to access the variables in the object

Using this allows us to access variables inside the object

var person = {
    namer: 'Joe'.sayNmae: function() {
        console.log(this.namer); }}var namer = 'bill'
person.sayNmae(); / / zhang SAN
Copy the code

This is because the this in the method refers to the object of the method

thisIt’s an object

classification

This is divided into this in the global scope and this in the function

This in the global scope refers to a Windows object

The reference to this in a function is a little bit more complicated, so we’re going to look at the reference to this in a little bit more detail

2. In the functionthisThe point to

The reference to this is determined when we call the function. Different methods called result in different references to this

Call way This points to the
Ordinary function calls window
Constructor call Instance objectsMethods inside the prototype object also point to the instance object
Object call method The object to which the method belongs
Event binding function Bind event object
Timer function window
Execute function immediately window
Arrow function Arrow functionthisThat’s the outer functionthis

1. Ordinary functions

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

Return window object

constructors

// The constructor this refers to the instance object p
function Person() {}
// The methods inside the prototype object also point to the instance object
Person.prototype.say = function() {
    console.log(this);
}

var p = new Person()
p.say();  // Person {}
Copy the code

3. Object methods

var person = {
    namer: 'Joe'.sayNmae: function() {
        console.log(this.namer);
    }
}
person.sayNmae(); / / zhang SAN
Copy the code

When a function is called as a method of an object, this in the function is that object

However, if the object is assigned a global variable, this points to the window object

var namer = 'bill'
var p = person.sayNmae;
p(); / / li si
Copy the code

4. Event binding functions

var btn = document.querySelector('button')
btn.onclick = function() {
    console.log(this); // 
}
Copy the code

In the event binding function, this refers to the bound event, so click the button to output the Button event

5. Timer function

setTimeout(function() {
    console.log(this);
}, 500)
Copy the code

Print the Window object after 0.5 seconds

Execute the function immediately

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

The immediate function is also an ordinary function in nature, whose this naturally points to the Window object

Arrow function

The arrow function in ES6 has no execution context of its own, so the arrow function’s this is its outer function’s this

Note:

  • It’s in the outer function of the arrow functionthisIs not in the objectthis
  • If there is no outer function, thenthisThe default point towindowobject
var namer = 'bill'
var person = {
    namer: 'Joe',}// Arrow function
var sayNmae = () = > console.log(this.namer)
sayNmae();  / / li si 7

// Add arrow function
person.sayNmae = sayNmae
// Still access global variables
person.sayNmae(); / / li si
Copy the code

In the arrow function, this refers to the context in which the arrow function is defined. In both of the above calls, this refers to the window object because the arrow function is defined in window

3. Change inside the functionthisThe point to

Js provides several methods to change the direction of this inside a function. There are three common methods:

  • call()
  • apply()
  • apply()

3.1 call()methods

The call() method does two things: change the direction of this and call the function

var person = {
    name: 'Joe'
}

function foo(a, b) {
    console.log(this);
    console.log(a + b);
}
foo.call(person, 1.2)  // {name: 'zhang SAN'} 3
Copy the code

This is already pointing to the Person object

The main purpose of the Call method is to implement inheritance

3.2 apply()methods

func.apply(thisAry, [argsArray])
Copy the code
  • thisAry: specified when the func function is runthisvalue
  • argsArray: The value passed must be contained in the array
  • apply()The array is automatically converted to the numeric type we need
var person = {
    name: 'Joe'
}

function foo(a, b) {
    console.log(this);
    console.log(a + b);
}
foo.apply(person, [1.2]) // {name: 'zhang SAN'} 3
Copy the code

Apply () is often associated with arrays, such as extracting the maximum and minimum values of an array with built-in array objects

Math.max()Specifies that a single value must be passed in

var max = Math.max(1.20.3.10.15)
console.log(max);
Copy the code

We use Apply to split the array into individual values and pass them to Max to find the maximum value of the array

var arr = [11.20.3.10.15]
var max = Math.max.apply(Math, arr)
console.log(max);  / / 20

var min = Math.min.apply(Math, arr)
console.log(min);  / / 3
Copy the code

Point this in Apply to the function’s caller, Math


3.3 bind()methods

The best thing about bind() is that it doesn’t call a function, just like call()

func.bind(thisAry, arg1, arg2, ...) ;Copy the code
  • thisAry: specifies when the func function is runthisvalue
  • arg1,arg2: Passes a single parameter
var person = {
    name: 'Joe'
}

function foo(a, b) {
    console.log(this);
    console.log(a + b);
}
var f = foo.bind(person, 1.2) 
f();  // {name: 'zhang SAN'} 3
Copy the code

You can use bind if you don’t need to call a function immediately, but want to change the reference to this inside the function

Bind is also the most commonly used of the three methods

4,thisThere is a drawback

Bug: This in a nested function does not inherit this in an outer function

var namer = 'bill'
var obj = {
    namer: 'Joe'.show: function() {
        console.log(this.namer);  / / zhang SAN

        function foo() {
            console.log(this.namer);  / / li si
        }
        foo()
    }
}
obj.say()
Copy the code

As you can see, the show method’s this refers to its object obj, and the foo function’s this does not inherit its external function show’s this, but the global object Window

There are two solutions:

  1. Declare a variable to savethis
  2. Using the arrow function

Method one “declare a variable that to hold this

var namer = 'bill'
var obj = {
    namer: 'Joe'.show: function() {
        console.log(this.namer);  / / zhang SAN
		
        / / save this
        var that = this  
        
        function foo() {
            console.log(that.namer);  / / zhang SAN
        }
        foo()
    }
}
obj.say()
Copy the code

Method two: arrow function

The arrow function has no context of its own, so where the arrow function is defined, its context is there, so where does this point to

var namer = 'bill'
var obj = {
    namer: 'Joe'.say: function() {
        console.log(this.namer); / / zhang SAN
        var foo = () = > {
            console.log(this.namer); / / zhang SAN
        }
        foo()
    }
}
obj.say()
Copy the code

Applet: When we click this button, immediately disable this button, 2 seconds later to enable it

When you think about delays, the first thing that comes to mind is using setTimeout or setInterval

var btn = document.querySelector('button')
// Click the button
btn.onclick = function() {
    // The event binding function, this refers to the bound event BTN
    this.disabled = true;  // Disable the button first
    setTimeout(function() {
        // This refers to the window object
        this.disabled = false;
    }, 2000)}Copy the code

According to our above analysis, this way is absolutely GG, can not achieve the effect

The event object referred to by this in the event function is disabled after the button is clicked; The problem arises when this in the delay function refers to the window object

So we need to access the event object in the delay function. There are four ways:

  1. Direct use ofbtnThe event object
  2. savethis
  3. Using the arrow function
  4. usingbindModify thethisPoint to the

Method 1: Use the BTN event object

var btn = document.querySelector('button')
btn.onclick = function() {
    this.disabled = true;
    var that = this
    setTimeout(function() {
        btn.disabled = false;
    }, 2000)}Copy the code

Disadvantages: Event name changes, the following will be modified, very inconvenient, not recommended

Method 2: Savethis

btn.onclick = function() {
    this.disabled = true;
    var that = this  / / save this
    setTimeout(function() {
        that.disabled = false
    }, 2000)}Copy the code

Disadvantages: Need to open up new memory space to store that, increase the code

Method 3: Arrow function

btn.onclick = function() {
    this.disabled = true;
    // Arrow function
    setTimeout(() = > {
        this.disabled = false
    }, 1000)}Copy the code

The arrow function defined in the event click function, whose this points to the event object where its context resides

Method four: usebindModify thethisPoint to the

Bind has two main features: it changes the this pointer, and it doesn’t call a function

Because all we need to do is change the this pointer in the delay function, we don’t need to call the function, call the function and let the delay function take care of itself

btn.onclick = function() {
    this.disabled = true;
    setTimeout(function() {
        this.disabled = false
    }.bind(this), 2000)}Copy the code

conclusion

  1. In non-strict mode, of the functionthisPoint to thewindowObject; In strict mode, the functionthisThe value ofundefined
  2. callandapplyWill execute the function itself,bindIt does not. It returns a new function that has been bound to a new onethis
  3. Arrow functions are like parasites, defined in their contextthisWho is to
  4. In the inheritance functionthisDoes not inherit its outer functionthisvalue