As I understand it this in JavaScript points to

  • 2021-08-10 06:52:53
  • OfStack

Preface

In JS this Pointing is a frequently asked question, and there are many articles about this on the Internet. This article sorts out what I understand this And one of the things I'm wondering about this Problem.

this pointing

How many this The point-to-point problem that almost every article will talk about, such as direct call as a function, method call as an object, new Operator in execution this Behavior. A more general statement is that, this Points to the object that calls the function directly. In fact, it is also very easy to understand, that is, why it is necessary this This keyword means that we need to operate on the object calling the function inside the function. But sometimes we encounter situations that are not like books or mdn Typical situations encountered in, this Our behavior may make us feel a little confused.

Direct call of function

When we call a declared function directly, then in non-strict mode, the internal of the function this Points to global objects, which is in browser environment this 1 Object.


function f1(){
 return this;
}
// In the browser: 
f1() === window; // In the browser, the global object is window

// In Node Medium: 
f1() === global;

This phenomenon is understandable when the function is defined in the global environment, because the function defined in the global environment is actually a property mounted on the global object, compared with the above this 2 It can also be understood as this 3 . But I think the behavior under the strict mode is more in line with this The purpose of this keyword, especially if our function may be defined and called in a non-global environment (such as another function), in which case this Also points to this 1 Is not very reasonable. So in strict mode, a function directly calls its this It points to this 8 If we want to get the result in non-strict mode, the method we call the function should be changed to this 9 And if the function is defined in a non-global environment, it always returns this 8 . I think such behavior is more logical.


'use strict'
function d () {
 function e() {
  console.log(this)
 }
 console.log(this)
}

d()
//undefined
//undefined

window.d()
//Window{}
//undefined

Use here in global mode this 1 Just for testing, the actual use is to use strict mode locally in the function as much as possible, and strict mode under the global situation can easily lead to errors.

Function is called as a property of an object

This is also a very common scenario in code, which I think is better understood than function calls and helps us understand the behavior of this. Simply put, it is this It points to this 3 The object from which the function is called. And note that this has nothing to do with where the function is defined. Let's see this Which is where the function is called.


// Define inside the object 
var o = {
 prop: 37,
 f: function() {
 return this.prop;
 }
};

console.log(o.f()); // 37

// Define outside the object 
var o = {prop: 37};

function independent() {
 return this.prop;
}

o.f = independent;

console.log(o.f()); // 37

// Defined inside an object, but referenced to an external variable and executed 
var o = {
 prop: 37,
 f: function() {
  console.log(this)
 return this.prop;
 }
};
var prop = 100;
var m = o.f;
console.log(m());
//Window{}
//100

I gave the above paragraph this 3 These two words are bolded to mean that when we find and call a function by nesting the properties of multiple objects, the last object closest to the function is the function this The direction of.


var o = {
 a:10,
 b:{
  a:12,
  fn:function(){
   console.log(this.a); //12
  }
 }
}
o.b.fn();

var o = {
 a:10,
 b:{
  // a:12,
  fn:function(){
   console.log(this.a); //undefined
  }
 }
}
o.b.fn();

The reason why I say this scene can help us understand is that it reflects this The nature of this keyword. this 8 The function in is also a kind of object, and the active object in our execution environment only stores a reference of the function object. If this reference is stored in the attribute of an object in the active object (that is, we find the function through the attribute of an object in the active object), then when the function is executed, this Will point to this object, which is why the call of the multi-tier object is still the object closest to the function as this . Although in code our function is defined in an object, actually in memory, the object holds only a reference to the function, and the function itself is in a separate memory space. So what object do we find the function and execute the this Point to this object. The direct call above this Return this 8 It also makes sense.

Call through prototype

Sometimes we execute common functions through prototypes, which already conforms to our above logic. If we find the function through which instance, this points to that instance.


var o = {
 f: function() { 
 return this.a + this.b; 
 }
};
var p = Object.create(o);
p.a = 1;
p.b = 4;

console.log(p.f()); // 5

Arrow function

The arrow function does not have its own this In the arrow function this Is in the execution environment in which it is located this ( mdn Is written in a closed lexical environment), when you encounter the arrow function this When you are not sure, you can imagine replacing this arrow function with console.log(this) The output of this console is in the arrow function this And the this of the arrow function is bound and does not change (sometimes it seems to change where it is located context Changed). Another point to note is that using call , apply , bind To call the arrow function, the first parameter is meaningless, that is, it cannot be changed this If you still need to use it, the first parameter should be passed null . Look mdn The example given by.


var globalObject = this;
var foo = (() => this);
console.log(foo() === globalObject); // true

//  Then the code above 
//  Object as an object 1 Method calls 
var obj = {foo: foo};
console.log(obj.foo() === globalObject); // true

//  Try using call To set this
console.log(foo.call(obj) === globalObject); // true

//  Try using bind To set this
foo = foo.bind(obj);
console.log(foo() === globalObject); // true

//  Create 1 Contains bar Method's obj Object, 
// bar Return 1 Functions, 
//  This function returns this , 
//  The returned function is created as an arrow function, 
//  So its this Is permanently bound to its outer functions this . 
// bar Can be set in the call, which in turn sets the value of the return function. 
var obj = {
 bar: function() {
 var x = (() => this);
 return x;
 }
};

//  As obj Object's 1 Methods to call bar , put its this Bind to obj . 
//  Assigns a reference to the returned function to fn . 
var fn = obj.bar();

//  Direct call fn Without setting this , 
//  Usually ( That is, the arrow function is not used ) Default to global object 
//  If in strict mode; Otherwise undefined
console.log(fn() === obj); // true

//  But note that if you just quote obj The method, 
//  Without calling it 
var fn2 = obj.bar;
//  Then after calling the arrow function, this Point window Because it starts from  bar  Inherit this . 
console.log(fn2()() == window); // true

Other circumstances

There are still one situation that I think is relatively simple, so I have mentioned it once.
1. When a function is used as an event handler, its this Points to the element that triggered the event.
2. When code is inlined on-event When processing a function call, its this points to the DOM element where the listener is located, noting that only the outermost this Well, if there are nested functions inside, the nested function's this Still points to global objects in non-strict mode.
3. In the constructor this See the parsing and implementation of the new operator in the previous article JavaScript
4. bind , this4 And apply All 1 sample, function of this Is bound to the first parameter.

Summarize

That's what I've summed up this7 In this If there are any omissions or mistakes, please correct them.


Related articles: