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.applymethodcall/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 FruitBcallfruitA的changemethod, 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"