Detailed explanation of this keyword in JS

I recently studied this in JavaScript and got a little confused, but I found a good summary article and share it with you: https://segmentfault.com/a/1190000003046071

This article mainly explains the pointing problem of this keyword in JS (in browser environment).

First of all, you must understand the several ways to call functions in JS:

  • Ordinary function call
  • Called as a method
  • Called as a constructor
  • Use the apply/call method to call
  • Function.prototype.bind method
  • es6 arrow function

But no matter which method the function is called,Please remember one thing: whoever calls this function or method, the this keyword points to whom

Next, we will discuss these different situations separately:

Ordinary function call

 function person() { this.          name='xl'; console.log(this);        console.log(this.name); } person();   //Output window xl   

In this codepersonThe function is called as a normal function, in factpersonis as a global objectwindowA method to call, that iswindow.person();
So this place iswindowThe object calledpersonmethod, thenpersonin the functionthisthat is to saywindow,at the same timewindowIt also has another attributename, the value isxl.

 var           name='xl'; function person() { console.log(this.name); } person();   //Output xl

Same placepersonaswindowmethod to call, a global variable is defined at the beginning of the codename, the value isxl, which is equivalent towindowan attribute ofwindow. name='xl', and because callingpersonwhenthisis pointing towindow, so here will be outputxl.

Called as a method

In the above code, the ordinary function call is aswindowObject methods are called. obviouslythisThe keyword points towindowobject.

Let’s look at other forms

 var           name='XL'; var     person={     name:'xl', showName:function() { console.log(this.name); } } person.showName();  //Output xl //Here is the person object calling the showName method. Obviously this keyword points to the person object, so name will be output. var  showNameA=person.showName; showNameA();  //Output XL //Here, the person.showName method is assigned to the showNameA variable. At this time, the showNameA variable is equivalent to an attribute of the window object. Therefore, when showNameA() is executed, it is equivalent to window.showNameA(), that is, the window object calls the showNameA method, so the this keyword points to the window.

Change it to another form:

 var  personA={  name:'xl', showName:function() { console.log(this.name); } }  var  personB={  name:'XL', sayName:personA.showName } personB.sayName();  //Output XL //Although the showName method is defined in the personA object, it is called in the personB object when it is called, so this object points to

Called as a constructor

 function Person(name){ this.name=name; }  var  personA=Person('xl');        console.log(personA.name);  // output undefined console.log(window.name);//Output xl //The above code does not perform the new operation, which is equivalent to calling the Person('xl') method on the window object. Then this points to the window object and performs the assignment operation window.name='xl'. var  personB=new    Person('xl');        console.log(personB.name); // output xl //Explanation of this part of the code is below 

new operator

 //The following code simulates the internal process of the new operator (instantiated object) function person(name){ var  o={}; o.__proto__=Person.prototype;  //Prototypal inheritance  Person.call(o,name);  return  o; }  var  personB=person('xl');        console.log(personB.name);  // output xl 
  • personInside, first create an empty object o, and add o'sprotoPoint to Person.prototype to complete inheritance of prototype properties and methods
  • Person.call(o,name)Here is the functionPersonasapply/callCall (specific content below), willPersonin objectthisChange it to o and it is completedo.name=nameoperate
  • Return object o.
    Therefore `person('xl')` returns an object that inherits the properties and methods on `Person.prototype` and has the `name` attribute as'xl'object and assign it to the variable `personB`. So `console.log(personB.name)` will output'xl' 

Call/apply method call

In JS, functions are also objects, so functions also have methods. Inherited from Function.prototypeFunction.prototype.call/Function.prototype.applymethod
call/applyThe biggest effect of methods is to changethisKeyword pointing.

Obj.method.apply(AnotherObj,arguments);

 var           name='XL'; var  Person={  name:'xl', showName:function() { console.log(this.name); } } Person.showName.call();  //Output 'XL' //The first parameter in the call method here is empty and points to window by default. //Although the showName method is defined in the Person object, after using the call method, this in the showName method points to the window. Therefore, 'XL' will be output in the end;
  function FruitA(n1,n2){  this.n1=n1;  this.n2=n2;  this.change=function(x,y){ this.n1=x;  this.n2=y; } }  var  fruitA=new  FruitA('cheery','banana');        var  FruitB={  n1:'apple', n2:'orange'  }; fruitA.change.call(FruitB,'pear','peach');        console.log(FruitB.n1);  //Output pear console.log(FruitB.n2);// output peach

FruitBcallfruitAchangemethod, willfruitAinthisbind to objectFruitBsuperior.

Function.prototype.bind() method

 var           name='XL'; function Person(name){ this.name=name;   this.sayName=function() { setTimeout(function() { console.log('my name is '+this.name); },50) } }  var     person=new    Person('xl'); person.sayName()  //Output "my name is XL"; //The setTimeout() timing function here is equivalent to window.setTimeout(), which is called by the global object window. Therefore, this points to window, and this.name is XL.  

So how can I output'my name is xl'Woolen cloth?

 var           name='XL'; function Person(name){ this.name=name;   this.sayName=function() { setTimeout(function() { console.log('my name is '+this.name); }.bind(this),50) //Pay attention to the bind() method used here. The this of the anonymous function in setTimeout always points to the Person object.  } }  var     person=new    Person('xl'); person.sayName();  //Output "my name is xl";

heresetTimeout(function(){console.log(this.name)}.bind(this),50);,Anonymous function usebind(this)A new function is created after the method. No matter where this new function is executed,thisall pointed toPerson, rather thanwindow, so the final output is "my name is xl" instead of "my name is XL"

A few other things to note:
setTimeout/setInterval/anonymous function executionwhen,thisDefault points towindow object, unless the point of this is manually changed. In "Javascript Advanced Programming", it is written: "The code for timeout calls (setTimeout) are executed in the global scope, so the value of this in the function points to the window object in non-strict mode, and points to undefined in strict mode. This article is all in non-strict mode.

 var           name='XL'; function Person() { this.          name='xl'; this.showName=function() { console.log(this.name); } setTimeout(this.showName,50); }   var     person=new   Person();   //Output 'XL' //In the setTimeout(this.showName,50) statement, the this.showName method will be executed with a delay //this.showName method is the method defined in the constructor Person(). After 50ms, the this.showName method is executed, and this in this.showName now points to the window object. will output 'XL';

Modify the above code:

 var           name='XL'; function Person() { this.          name='xl'; var   that=this; this.showName=function() { console.log(that.name); } setTimeout(this.showName,50) }  var     person=new   Person();   //Output 'xl' //Here, assign this to that in the Person function, that is, let that save the Person object. Therefore, during the execution of setTimeout(this.showName,50), console.log(that.name) will output the attribute 'xl' of the Person object.

Anonymous function:

 var           name='XL'; var     person={     name:'xl', showName:function() { console.log(this.name); } sayName:function() {(function(callback){ callback(); }  )(this.showName) } } person.sayName();  //Output XL
 var           name='XL'; var     person={     name:'xl', showName:function() { console.log(this.name); } sayName:function() { var   that=this; (function(callback){ callback(); })(that.showName) } } person.sayName();  //Output 'xl' //The execution of anonymous functions also points to window by default, unless the binding object of this is manually changed.

Eval function

When this function is executed, this is bound to the object in the current scope.

 var           name='XL'; var     person={     name:'xl', showName:function() { eval('console.log(this.name)'); } } person.showName();  //Output 'xl' var  a=person.showName; a();  //Output 'XL'

arrow function

es6inthisPointers are fixed and always point to external objects, because arrow functions do notthis, so it cannot proceed by itselfnewInstantiation, but also cannot be usedcall, apply, bindWaiting for a way to changethispointing

 function Timer()  { this.seconds =  0; setInterval(  ()    => this.seconds++,  1000); }   var  timer =  new  Timer(); setTimeout(  ()    => console.log(timer.seconds),  3100);        // 3  The callback function within setInterval() inside the constructor,thisAlways points to the instantiated object and obtains the seconds attribute of the instantiated object. Each time1The value of this attribute s will increase1. Otherwise it ends up in3After executing the setTimeOut() function after s, the output is0

This siteOriginal articleAll follow "Attribution-NonCommercial-ShareAlike 4.0 License (CC BY-NC-SA 4.0)". Please keep the following tags for sharing and interpretation:

Original author:Jake Tao,source:"Detailed explanation of this keyword in JS"

140
0 0 140

Further reading

Leave a Reply

Log inCan comment later
Share this page
Back to top