this в функциях относится к тому, как вызывается функция. Хорошо, а как можно вызвать обычную функцию? Мы увидим это ниже. На это также влияют объекты, классы и стрелочные функции или обычные функции.

Я также расскажу о классах, объектах и ​​стрелочных функциях.

Вызов функций:

Функции можно вызывать как функцию, как метод (функцию в объекте), с помощью new и с помощью apply/call/bind.

Как функция:

function hey (){
  console.log(this);
}
hey();
//prints the global this (window or globalThis in Node)
//If the code is set to use strict, then this will be undefined.

Как метод (внутри объектов):

let obj = {
  prop1: "hello",
  prop2: "bye",
  prop3: function (myargs) {
    console.log(this);
    console.log(arguments);
  }
}
obj.prop3("I am Argument");
//the this now refers to the object itself.
{ prop1: 'hello', prop2: 'bye', prop3: [Function: prop3] }
[Arguments] { '0': 'I am Argument' }

Как конструктор:

Когда функция используется в качестве конструктора, ее this является одним из создаваемых объектов.

Во-первых, давайте посмотрим на this обычной функции, которая получает this изменение в коде.

//call function regularly
function regF(){
  this.a = "hey";
  console.log("this calling function regularly");
  console.log(this);
}
regF();
//displays
//this calling function regularly
//Object [global] {
// global: [Circular],
// …
// a: ‘hey’,
//...

Теперь у нас есть та же функция, но мы будем использовать ее как конструктор.

//use function as constructor but don't change anything
function regF(){
  this.a = "hey"; 
  console.log("this calling function regularly");
  console.log(this); 
}
let obj1 = new regF();
console.log(obj1);
//displays
//this calling function regularly
//regF { a: 'hey' }
//regF { a: 'hey' }

Затем

//use new but now change the value of a.
function regF(){
  this.a = "hey"; 
  console.log("this calling function regularly");
  console.log(this); 
}
let obj1 = new regF();
obj1.a = "Not so hey anymore";
console.log(obj1);
//displays
this calling function regularly
regF { a: 'hey' }
regF { a: 'Not so hey anymore' }

Теперь функция устанавливает это, но потом возвращает что-то другое.

function regF(){
  this.a = "hey";  
  return {a: "hey hey hey"};
}
let obj3 = new regF();
console.log(obj3); 
//displays { a: ‘hey hey hey’ }

Что бы мы ни установили в функции, используемой в качестве конструктора, это не будет иметь значения, потому что важно то, что мы вернем.

Как вызвать/применить/привязать:

const obj = { a: 'Custom' };
var a = 'Global';
function whatsThis() {
  console.log(this);  
}
whatsThis(); // the global this
whatsThis.call(obj); //{ a: 'Custom' } the one from the obj

С помощью bind мы можем привязаться к новому объекту только один раз:

function f() {
  console.log(this);
}
const g = f.bind({ a: 'bind 1' });
g();//shows bind 1

Если мы создадим другую функцию из этой и попытаемся привязаться к чему-то другому:

// bind only works once!,
const h = g.bind({ a: 'bind 2 ' }); 
h(); // still shows bind 1

Теперь, если мы создадим объект, который содержит элемент, а также ранее созданные функции:

function f() {
  console.log(this);
}
const g = f.bind({ a: 'bind 1' });
const h = g.bind({ a: 'bind 2 ' }); 
const o = { a: 37, f, g, h };
o.f();
//will show the for the object:
{
  a: 37,
  f: [Function: f],
  g: [Function: bound f],
  h: [Function: bound bound f]
}

Если мы вызовем функцию g из объекта, мы получим исходную привязку:

function f() {
  console.log(this);
}
const g = f.bind({ a: 'bind 1' });
const h = g.bind({ a: 'bind 2 ' }); 
const o = { a: 37, f, g, h };
o.g(); // { a: 'bind 1' }, not the 37
//if we had done const o = { b: 37, f, g, h };
//we would still get { a: 'bind 1' }
//o.h() will also have { a: 'bind 1' }

Это в классах

Классы — это функции под капотом, но не все точно так же.

В конструкторе класса это обычный объект, и к его прототипу добавляются любые НЕстатические методы. Статические методы не являются свойствами this. Они являются свойствами самого класса.

class Example {
  constructor() {
    const proto = Object.getPrototypeOf(this);
    console.log(this);    
    console.log(Object.getOwnPropertyNames(proto));
  }
  first(){}
  second(){}
  static third(){}
}
new Example();
//display
//Example{}
//['constructor', 'first', 'second']

Конструкторы производных классов по умолчанию не получают this binding. Мы можем позвонить super() мы можем получить это. Вызов this до вызова super() вызовет ошибку. Некоторые сценарии:

Учитывая эту базу для всех примеров:

class Base {
  prop1 = "prop1 in base";
}

У нас может быть производный класс без конструктора, и все будет в порядке.

class Derived1NoConst extends Base {}
console.log(new Derived1NoConst());
//Derived1NoConst { prop1: 'prop1 in base' }

Теперь у нас есть этот класс без конструктора, но возвращающий объект, все будет в порядке:

class Derived2ConstAndReturnsObj extends Base {
  constructor() {
    return {a: 5};
  }
}
console.log(new Derived2ConstAndReturnsObj());
//{ a: 5 }

Теперь у нас есть класс, который ИМЕЕТ конструктор, НО НЕ возвращает объект. Не в порядке.

class Derived3ConsNoRet extends Base {
  constructor() {}
}
console.log(new Derived3ConsNoRet());
//return error
ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor

Чтобы исправить вышеперечисленное, вызовите super:

class Derived3ConsNoRet extends Base {
  constructor() {
    super()
  }
}
console.log(new Derived3ConsNoRet());
//Derived3ConsNoRet { prop1: 'prop1 in base' }

Стрелочные функции

Этот пример будет иметь this , что и его «родитель», который является глобальным.

console.log(this);//{}
const theThis = this;
//the function just returns this
const foo = () => this;
console.log(foo()); //{}
console.log( foo() === theThis);//true

если мы поместим эту функцию в объект, у нас все еще будет это.

const theThis = this;
const foo = () => this;
const obj = { func: foo };
console.log(obj.func() === theThis); // true

Посмотрите на этот код. У меня есть функция, которая изменяет свой this , чтобы иметь пару свойств, одно из которых является функцией стрелки. Функция стрелки имеет this родительской функции.

const globalThis = this;
function regFunc(){
  let funcThis = this;
  this.a = "hello";  
  console.log(this); //regFunc { a: 'hello' }
  console.log(this === funcThis); //true
  console.log(this === globalThis);//false
  this.myf = ( () => {
    console.log(this);//regFunc{a:'hello',myf: [Function]}
    console.log(this === funcThis);//true
    console.log(this === globalThis);//false
  })  
}
//regFunc()
var a = new regFunc();
a.myf()

Аналогично, если я сделаю это, за исключением того, что this внутри функции не включает myf: [Function]

const globalThis = this;
function regFunc(){
  let funcThis = this;
  this.a = "hello";  
  console.log(this); //regFunc { a: 'hello' }
  console.log(this === funcThis); //true
  console.log(this === globalThis);//false
  return ( () => {
    console.log(this);//regFunc { a: 'hello' }
    console.log(this === funcThis);//true
    console.log(this === globalThis);//false
  })  
}
//regFunc()
var a = new regFunc();
a()

Как обработчик событий

this устанавливается на элемент, на котором находится прослушиватель. В некоторых браузерах это будет работать динамически только при использовании addEventListener. Вот почему вы можете делать вещи this.style.color = «red».

Это то, что у меня есть на данный момент. Я уверен, что снова забуду, так что буду возвращаться к этому снова и снова.