This article is expected to take 15-20 minutes, including time to perform code validation. It is highly recommended that you read the code carefully and execute it manually to verify the results of different actions. It’s not easy to organize and verify, so if you learn something new, please give it a thumbs up. If you have any questions about this after reading this, please leave a comment at the bottom

The function’s this keyword behaves slightly differently in JavaScript than in other languages, and there are also some differences between strict and non-strict modes.

  • The way the function is called is determinedthisThe value of the.
  • thisCannot be assigned during execution, and every time a function is calledthisThe values of may also be different.
  • ES5 introducedbindMethod to set the functionthisValue regardless of how the function is called,
  • ES2015 introduced supportthisArrow function for lexical parsing (which is set within the closed execution environmentthisThe value).

This refers to the environment object in which the code is currently executing. In non-strict mode, this always refers to an object, and in strict mode can be any value

The global environment

This refers to the global object in the global execution environment (outside any function body), whether in strict mode or not.

// In the browser, the window object is also a global object:
console.log(this= = =window); // true

a = 37;
console.log(window.a); / / 37

this.b = "MDN";
console.log(window.b)  // "MDN"
console.log(b)         // "MDN"
Copy the code

You can use globalThis directly to get the globalThis object in different environments (that is, the global object itself)

Function of the environment

Inside a function, the value of this depends on how the function is called.

A simple call

In non-strict mode, the function is called directly in the global scope. The value of this is not set by the call, so the value of this points to the global object by default.

If the function name is not preceded by anything, it defaults to a simple call,

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

// In Node:
f1() === global;   
Copy the code

In strict mode, this will retain its value when it enters the execution environment, so the following this will default to undefined.

function f2(){
  "use strict"; // Here is strict mode
  return this;
}

f2() === undefined; // true
Copy the code

Strictly, if this is not defined by the execution context, it will remain undefined.

usecallorapplyA method can be used in its bodythisBind to an object.

This will be bound to an object as the first argument to call and apply.
var obj = {a: 'Custom'};

// This property is defined in the global object.
var a = 'Global';

function whatsThis(arg) {
  return this.a;  // The value of this depends on how the function is called
}

whatsThis();          // 'Global'
whatsThis.call(obj);  // 'Custom'
whatsThis.apply(obj); // 'Custom'
Copy the code

If the value passed to this is not an object, JavaScript tries to convert it to an object using the internal ToObject operation. So, if the value passed is a raw value like 7 or ‘foo’, then the relevant constructor will be used to convert it to an object, so the raw value 7 will be converted to an object like new Number(7), and the String ‘foo’ will be converted to new String(‘foo’).

bindmethods

ECMAScript 5 introduces function.prototype.bind (). Calling f.bind(someObject) creates a function with the same body and scope as f, but in this new function, this is permanently bound to the first argument of bind, regardless of how the function is called.

function f(){
  return this.a;
}

var g = f.bind({a:"azerty"});
console.log(g()); // azerty

var h = g.bind({a:'yoo'}); // Bind only works once!
console.log(h()); // azerty

var o = {a:37.f:f, g:g, h:h};
console.log(o.a, o.f(), o.g(), o.h()); // 37, 37, azerty, azerty
Copy the code

Methods as objects

When ordinary functions are called as methods in an object, their this is the object on which the function was called.

In the following example, when o.f() is called, the this inside the function is bound to the O object.

var o = {
  prop: 37.f: function() {
    return this.prop; }};console.log(o.f()); / / 37
Copy the code

Note that the this inside the function refers to the object calling the function, regardless of where the function is located. Take the following example:

// It is recommended to run the following code from the browser console, node environment you will be confused, such as me

var prop = 10; 
const func = o.f;

// Call the function directly in the global environment
console.log(func()); / / 10

// Define a new object
const o1 = {
  prop: 15
}

// point func in o1 to f in o
o1.func = o.f;

// call o1 with this pointing to o1
console.log (o1. Func ());/ / 15
Copy the code

This in the prototype chain

The same concept applies to methods defined somewhere along the object prototype chain. If the method exists on an object’s prototype chain, then this refers to the object on which the method was called, just as it does on the object.

As a constructor

When a function is used as a constructor (using the new keyword), its this is bound to the new object being constructed.

function C(){
  this.a = 37;
}

var o = new C();
console.log(o.a); // logs 37
Copy the code

As a DOM event handler

When a function is used as an event handler, its this points to the element that triggered the event (some browsers do not follow this convention when dynamically adding listeners using functions that are not addeventListeners).

// When called, turn the associated element blue
function bluify(e){
  console.log(this === e.currentTarget); / / is always true

  // True if currentTarget and target are the same object
  console.log(this === e.target);        
  this.style.backgroundColor = '#A5D9F3';
}

// Get a list of all the elements in the document
var elements = document.getElementsByTagName(The '*');

// Use Bluify as the click-listening function for the element, which turns blue when the element is clicked
for(var i=0 ; i<elements.length ; i++){
  elements[i].addEventListener('click', bluify, false);
}
Copy the code

Nested function

This inside a nested function has nothing to do with the this of the environment in which the function is called

function foo() {
  console.log(this) 
  function boo() {
    console.log(this) 
  }
  boo()
}

// Call directly
foo() // window window

/ / the new object
const f = new foo() // foo instance window
Copy the code

A function that is called from within a function. Since there is no explicit object to call, this points to global.

Timers and microtasks

The simple function called this in the microtask refers to window strictly to undefined, while the timer callback always refers to window under strict or non-strict circumstances,

Simple functions called in asynchronous tasks are queued and eventually called by the global environment

Arrow function

In the arrow function, this is consistent with this in the enclosing lexical context.

In the global environment

In the global code, it will be set as a global object:

var globalObject = this;
var foo = (a)= > this;

// called in global code
console.log(foo() === globalObject); // true

// as a method call to the object
var obj = {foo: foo};
console.log(obj.foo() === globalObject); // true

// Use call to set this
console.log(foo.call(obj) === globalObject); // true

// Use bind to set this
foo = foo.bind(obj);
console.log(foo() === globalObject); // true
Copy the code

Note: It is invalid to pass this to call, bind, or apply to call the arrow function operation.

The arrow function does not create its own this; it only inherits this from the upper level of its scope chain.

Please execute the following code in the console

Arrow functions as object methods

// The same object
var o = {
  prop: 37.f: function() {
    return this.prop;
  },
  g: (a)= > {
    return this.prop; }};// call it separately
console.log(o.f()); // this refers to object O
console.log(o.g()); // undefined, this refers to the global

// Declare prop globally
var prop = 10;

// call it separately
console.log(o.f()); / / 37
console.log(o.g()); / / 10
Copy the code

You can take a look at the object.defineProperty () example to see why this points globally inside the arrow function in the Object method:

'use strict';
var obj = {
  a: 10
};

Object.defineProperty(obj, "b", {
  get: (a)= > {
    console.log(this.a, typeof this.a, this);
    return this.a+10; 
   // represents the global object 'Window', so 'this.a' returns 'undefined'}});Copy the code

The arrow function is executed inside the function

In the following code, the value of this in the function passed to setInterval is the same as that in the enclosing function:

function Person(){
  this.age = 0;

  setTimeout((a)= > {
    this.age++; / / | this | to p instance correctly
  }, 1000);
}

var p = new Person();
p.age; / / 1
Copy the code

Another way to call:

// Declare global variables
var prop = 10;

// Declare an object
const o1 = {
  prop: 15
}


function func1() {
  const prop = 11;
  const te = (a)= > {
    return this.prop;
  }
  return te();
}

console.log(func1()) / / 10
console.log(func1.call(o1)) / / 15
Copy the code

As you can see from the above code, the arrow function defined inside the function inherits this from the outer function. In this case, the arrow function’s this is not fixed, but will be determined when the outer function func1 executes.

Another way to call:

// Declare global variables
var prop = 10;

// Declare an object
const o1 = {
  prop: 15
}

function func1() {
  const prop = 11;
  const te = (a)= > {
    return this.prop;
  }
  return te;
}

Func1 is called in the global environment
o1.func = func1();
console.log(o1.func()) // 10, arrow function this points to the global object

Func1 is func1 in o1
o1.func1 = func1;
console.log(o1.func1()()) // 15, arrow function this points to o1
Copy the code

Conclusion: The this of the arrow function inside the function inherits the this of the outer function and is therefore not fixed, but is determined when the outer function func1 executes.

Note that when this.te = () => {return this.prop} is used, te is an object property and not a local variable of the function, so the internal this no longer inherits from the function, but points to the global, referring to the arrow functions as object methods section above.

Finally, I’ll show you how to make the arrow function method inside an object’s this not fixed, that’s right, define the object inside the function and declare the method inside the object.

// Declare global variables
var prop = 10;

// Declare an object
const o1 = {
  prop: 15
}

function test(){
  const prop = 20;
  const o2 = {
    prop: 30.f: (a)= > {
      return this.prop; }}return o2.f();
}

// Call in the global environment
console.log(test()) / / 10

// call with o1
console.log(test.call(o1)) / / 15
Copy the code

Now do you see where this is going to point to?

Related series: Front End Foundation from scratch journey (super detailed, constantly updated ~)

If you learn something new, please give the author a thumbs up

Reference Documents:

this