preface

The “this” reference in JavaScript is a headache for many beginners, and it is also a frequently asked question in interviews, because if you do not thoroughly understand the “this” reference, it can lead to some immeasurable problems in development

concept

  1. Wherever the function is called, where this refers to the object on which it is called, okay
  2. In JavaScript, everything is an object and the runtime environment is an object (a Web application is a Window object), so functions are run under some object, and this is the object that points to the runtime of the function
  3. ()=>{} The arrow function’s this refers to the parent function’s this, and all binding rules apply to the arrow function

The principle of

I thought for a long time about how to write this piece, but later I found a very detailed explanation of the article, so let’s take it for a moment

Common function

function fun(){
    console.log(this.s);
}

var obj = {
    s:'1'.f:fun
}

var s = '2';

obj.f(); / / 1
fun(); / / 2
Copy the code

In the above code, fun is called twice, obviously with different results;

In a call to obj.f(), this refers to the object obj because the runtime environment is inside obj;

When fun() is called in the global scope, this points to the global scope object window;

But most people won’t tell you why the direction of this changes, when the direction of this changes; Understanding these, the use of this will not be unexpected;

First of all, we should know that in JS, arrays, functions, objects are reference types, in the case of parameter passing is reference passing;

In the above code, the obj object has two properties, but the value types of the properties are different and their representations in memory are different;

When called, it looks like this:

For function in js can pass as a value and return, also can be used as an object and the constructor, all function at runtime to determine its current operating environment, this was born, so this will vary according to the running environment, at the same time, the function of this also can only be finalized at runtime environment;

Take a look at the following code, and you may understand more about the dynamic switching rule for this runtime environment:

var A = {
    name: 'Joe'.f: function () {
        console.log('Name:' + this.name); }};var B = {
    name: 'bill'
};

B.f = A.f;
B.f()   // Name: Li Si
A.f()   // Name: Zhang SAN
Copy the code

In the above code, the A.f attribute is assigned to B.f, where object A assigns the address of an anonymous function to object B;

So when called, the function points to objects A and B, depending on the environment in which it’s running

function foo() {
    console.log(this.a);
}
var obj2 = {
    a: 2.fn: foo
};
var obj1 = {
    a: 1.o1: obj2
};
obj1.o1.fn(); / / 2
Copy the code

The o1 property value of obj1 is the address of obj2, and the fn property value of obj2 is the address of foo.

Foo is called in obj2, so this refers to obj2;

Then, we will make a summary of several situations in which this is used most frequently, and the most common ones are basically the following five:

Object methods, event bindings, constructors, timers, call(), apply() methods of function objects;

The above explanation of this principle is that we use the object method of this to illustrate, here will not repeat the explanation, students who do not understand, please go back to read;

()=>{} arrow function

var a = 'window'

var obj1 = {
    a: 'obj1'.fn: () = >{
        console.log(this.a)
    }
}
var obj2 = {
    a: 'obj2'.fn:function(){
        console.log(this.a)
    }
}
obj1.obj2fn = obj2.fn

obj1.fn() // window always points to this in the declared parent scope
obj2.fn() // obj2 dynamically points to the calling object
obj1.obj2fn() // obj1 dynamically points to the calling object
obj1.fn.apply(obj2) // Window cannot be forced to bind this
obj2.fn.apply(obj1) // obj1 can be forced to bind this
Copy the code

This in the event binding

There are three types of event binding: inline binding, dynamic binding, and event listening.

Two cases of inline binding:

<input type="button" value=" button" onclick="clickFun()"> <script> function clickFun(){ So this refers to window; </script> <input type="button" value=" onclick="this"> <! The runtime environment is in the node object, so this refers to the node object -->Copy the code

The syntax of inline binding event is within the HTML node, binding in the way of node attribute, attribute name is the event name preceded by ‘on’, attribute value is an executable JS code segment; The most common attribute value is a function call;

When the event is triggered, the property value is executed as JS code. There is no clickFun function in the current runtime environment, so the browser needs to jump out of the current runtime environment and look for a function called clickFun and execute it. This inside the function refers to the global object Window. If this is not a function call and is used directly in the context of the current node object, then obviously this will refer to the current node object;

Dynamic binding and event listening:

<input type="button" value=" id=" BTN "> <script> var BTN = document.getelementById (' BTN '); btn.onclick = function(){ this ; // this refers to the node object} </script>Copy the code

A dynamically bound event is an anonymous function that reassigns the property of the node object (preceded by ‘on’), so the function is executed in the context of the node object. This naturally refers to the node object.

The principle of this pointing to the event listener is basically the same as that of dynamic binding, so it will not be explained.

Constructor this

function Pro(){
    this.x = '1';
    this.y = function(){};
}
var p = new Pro();
Copy the code

New a constructor and execute the internal code of the function is the process of this five steps. When the JS engine points to the third step, it will force this to point to the newly created object. Basic do not need to understand, because this is the GRAMMAR rules in JS, remember it can;

This in window timer

var obj = {
    fun:function(){
        this; }}setInterval(obj.fun,1000);      // This points to the window
setInterval('obj.fun()'.1000);  // This points to the obj object
Copy the code

SetInterval () is a built-in method on the Window object that takes two arguments. The first argument can be a function or a piece of executable JS code, and the second argument is the interval at which the previous function or code was executed.

In the above code, setInterval(obj.fun,1000) takes the fun of the obj object as its first argument. Since JS functions can be passed as values by reference, the address of the function is actually passed as an argument to setInterval. In other words, the first argument to the setInterval takes a function, and after 1000 milliseconds, the function will be running under the window object. That is, the caller of the function has become the window object, so this refers to the global Window object.

The first argument in setInterval(‘obj.fun()’,1000) is actually a piece of executable JS code passed in; 1000 ms later, when the JS engine executes this code, it will find the fun function through the obj object and call the execution, so the function environment is still inside the object obj, so this inside the function also refers to the obj object.

The call(), apply() methods of function objects

Functions provide call() and apply() methods as objects, which can also be used to call functions. Both methods take an object as an argument that specifies what the function refers to when called.

Call () method

Call (obj,arg1,arg2… argN); Parameter description: obj: The object to which this points, arg1,arg2… ArgN: List of arguments separated by a comma

var lisi = {names:'lisi'};
var zs = {names:'zhangsan'};
function f(age){
    console.log(this.names);
    console.log(age);
    
}
f(23);//undefined// Fix this in f to the zs object;
f.call(zs,32);//zhangsan
Copy the code

The apply () method

Apply (obj,[arg1,arg2… argN]) Parameter description: obj :this specifies the object to be pointed to. [arg1,arg2…argN] : Specifies the parameter list in the format of an array

var lisi = {name:'lisi'}; 
var zs = {name:'zhangsan'}; 
function f(age,sex){
    console.log(this.name+age+sex); 
}
// Fix this in f to the zs object;
f.apply(zs,[23.'nan']);
Copy the code

Note: Call and apply work the same way, only in the way function arguments are passed.

The best use of these two methods is basically to enforce the point to this when a function is called;

reference

After thoroughly understanding the this pointing problem in JavaScript, I wanted to write it myself, but later I found that it was no more than that, so I made an in-depth reference to the article and made some supplements