In fact, this is a cliché issue. There are a lot of articles about this. Actually, I thought I had figured it out, but yesterday, I still had a little doubt during the project. I thought about a detailed article I had collected and read in JavaScript weekly (there was a link later, and the Chinese translation on rare earths was attached) and another article recommended by a senior, so I looked at them and my understanding of this has indeed improved a little.
'this' in JavaScript is dynamic and is determined when the function is run, not when the function is declared. All functions can call 'this', which does not matter if the function belongs to an object. Regarding this, there are mainly four situations.
1. The method used as an object is called
If the function is a method that is regarded as an object, then this of the function points to the object;
var john = { firstName: "John" } function func() { alert(this.firstName + ": hi!") } john.sayHi = func john.sayHi() // this = johnThere is something worth noting here. When an object's method is taken out and assigned to a variable, the method becomes a function trigger, and this points to window or underfind (strict mode).
2. Call within the function
When this function has this, it actually means that it is called as a method. Calling between the two is equivalent to treating it as a window object. This points to window. It is worth noting that ES5 actually stipulates that this=undefined, and only browsers are still executed according to the old method (I test it in the latest version of Chrome, Safari, and Firefox all point to window (201607)), and use strict mode to point to undefined under Firefox;
func() function func() { alert(this) // [object Window] or [object global] or kind of.. }To pass this, () should be a reference type before, similar to obj.a or obj['a'], and cannot be anything else.
There is also a small pit here. When there is a function in the object's method, the function is actually triggered as a function mode, so this defaults to window (undefined in strict mode). The solution is to bind this to the function.
var numbers = { numberA: 5, numberB: 10, sum: function() { console.log(this === numbers); // => true function calculate() { // this is window or undefined in strict mode console.log(this === numbers); // => false return this.numberA + this.numberB; } return calculate(); }};numbers.sum(); // => NaN or throws TypeError in strict mode var numbers = { numberA: 5, numberB: 10, sum: function() { console.log(this === numbers); // => true function calculate() { console.log(this === numbers); // => true return this.numberA + this.numberB; } // use .call() method to modify the context return calculate.call(this); }};numbers.sum(); // => 153. Call in new
A variable that references an object actually saves a reference to the object, that is, the variable actually saves a pointer to the real data.
When using the new keyword, this change actually takes the following steps:
Create this = {}.
This may be changed during the execution of new, and then attributes and methods are added;
Returns this changed.
function Animal(name) { this.name = name this.canWalk = true } var animal = new Animal("beastie") alert(animal.name)It should be noted that if the constructor returns an object, then this points to the returned object;
function Animal() { this.name = 'Mousie'; this.age = '18'; return { name: 'Godzilla' } // <-- will be returned } var animal = new Animal() console.log(animal.name) // Godzilla console.log(animal.age)//undefinedIt is important to note here that don't forget to use new, otherwise a new function will not be created. Instead, it just executes the function, which is equivalent to a function call, and this actually points to window
function Vehicle(type, wheelsCount) { this.type = type; this.wheelsCount = wheelsCount; return this;}// Function invocationvar car = Vehicle('Car', 4); car.type; // => 'Car' car.wheelsCount // => 4 car === window // => true4. Clearly call this, use call and apply
This is the most JavaScript-inspired place.
The following code:
func.call(obj, arg1, arg2,...)
The first parameter will be used as the reference object of this, and the subsequent parameter will be used as the parameter of the function. The solution is to use bind.
function Animal(type, legs) { this.type = type; this.legs = legs; this.logInfo = function() { console.log(this === myCat); // => true console.log('The ' + this.type + ' has ' + this.legs + ' legs'); };}var myCat = new Animal('Cat', 4); // logs "The Cat has 4 legs"setTimeout(myCat.logInfo.bind(myCat), 1000); // setTimeout?? var john = { firstName: "John", incident: "Smith" } function func(a, b) { alert( this[a] + ' ' + this[b] ) } func.call(john, 'firstName', 'surname') // "John Smith"As for apply, it just passes in parameters in the square of the array, and the other parts are the same, as follows:
func.call(john, 'firstName', 'surname') func.apply(john, ['firstName', 'surname'])
They can also be used in class inheritance in ES5 to call the parent constructor.
function Runner(name) { console.log(this instanceof Rabbit); // => true this.name = name; } function Rabbit(name, countLegs) { console.log(this instanceof Rabbit); // => true // Indirectly called, the parent constructor Runner.call(this, name); this.countLegs = countLegs; } var myRabbit = new Rabbit('White Rabbit', 4); myRabbit; // { name: 'White Rabbit', countLegs: 4 }5..bind()
Compare the methods .apply() and .call(), both of which execute the function immediately, while the .bind() function returns a new method that binds this pre-specified and can delay the call.
The function of the .bind() method is to create a new function. The context during execution is the first parameter passed by .bind(), which allows the creation of a function that has this preset.
var numbers = { array: [3, 5, 10], getNumbers: function() { return this.array; }};// Create a bound functionvar boundGetNumbers = numbers.getNumbers.bind(numbers); boundGetNumbers(); // => [3, 5, 10] // Extract method from objectvar simpleGetNumbers = numbers.getNumbers; simpleGetNumbers(); // => undefined or throws an error in strict modeWhen using .bind(), you should note that .bind() creates an eternal context chain and is not modifiable. Even if a binding function uses .call() or .apply() to pass into other different contexts, it will not change the context of its previous connection, and rebinding will not play any role.
Only when the constructor is called, the binding function can change the context, but this is not a particularly recommended approach.
6. Arrow function
The arrow function does not create the context of its own execution, such that this depends on the external function it is defined at the time of definition.
Arrow functions cannot be changed after binding the context once, even if the context change method is used:
var numbers = [1, 2]; (function() { var get = () => { console.log(this === numbers); // => true return this; }; console.log(this === numbers); // => true get(); // => [1, 2] // Arrow functions use .apply() and .call() get.call([0]); // => [1, 2] get.apply([0]); // => [1, 2] // Bind get.bind([0])(); // => [1, 2] }).call(numbers);This is because the arrow function has a static context and will not change due to different calls. Therefore, do not use arrow functions to define methods
function Period (hours, minutes) { this.hours = hours; this.minutes = minutes; } Period.prototype.format = () => { console.log(this === window); // => true return this.hours + ' hours and ' + this.minutes + ' minutes'; }; var walkPeriod = new Period(2, 30); walkPeriod.format(); // => 'undefined hours and undefined minutes'refer to
Four scents of "this"
Gentle explanation of 'this' keyword in JavaScript
JavaScript This Mystery (Translation)
It is highly recommended that students who don’t understand it. Check out the above three articles, the third one is the translation of the second one. If you have any questions about this, you are welcome to discuss together, communicate and promote thinking and make progress together.