Узнайте, как «это» работает в JavaScript

В объектно-ориентированном программировании вы обычно создаете этот план со свойствами и методами, называемыми классом, и на основе этого класса вы можете создавать новые объекты. Теперь каждый объект, производный от класса, будет иметь похожую структуру, но их значения могут отличаться. Например, вы и я являемся производными от класса Person, и у каждого из нас будут методы ходьбы, разговора и еды. Но есть свойства, такие как имя, возраст или пол, которые могут быть или не быть одинаковыми для нас обоих.

Вы можете посмотреть видеоверсию этого поста здесь:

class Person {
    constructor(name, age, gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
    eat() { console.log(`${this.name} is eating`) }
    walk() { console.log(`${this.name} is walking`) }
    talk() { console.log(`${this.name} is talking`) }
}
const johnObj = new Person("John", 20, "Male");
johnObj.eat()  //John is eating

Итак, в этом примере внутри всех методов есть ключевое слово this. Ключевое слово this здесь относится к экземпляру класса, т. е. к объекту, который будет создан из этого класса.
Когда вы создаете объект из класса с помощью ключевого слова new, он вызывает функцию-конструктор и создает новый объект.
Теперь, если мы попытаемся запустить метод eat для экземпляра класса, ключевое слово this будет указывать на объект john. Таким образом, this.name в основном будет выглядеть как johnObj.name, в данном случае это Джон. Таким образом, на выходе мы получаем Джон ест.

Короче говоря, ключевое слово this представляет экземпляр класса. Но, поскольку мы работаем с Javascript, очевидно, что это будет нечто большее. this ведет себя по-разному в разных сценариях, и хотя вначале это может показаться немного запутанным, к концу этого сообщения в блоге все станет понятным. Итак, давайте начнем.

1. «это» внутри глобального контекста

В глобальном контексте thisalways относится к объекту окна. Больше ничего.

//Global context
console.log(window == this)  //true

2. «это» внутри функции

Внутри функции все становится немного сложнее. Значение this внутри функции зависит от того, как вызывается функция. Если функция является методом, то есть частью объекта, то this будет ссылаться на объект, вызывающий метод.

let person = {
  name : "John",
  walk : function(){ console.log(this.name + " walking") }
}
person.walk(); //John walking 

Если вместо этого у нас есть простая функция, а не метод, то по умолчанию this будет установлен на объект window.

function test(){
   console.log(this);    //Returns the window object   
   return this;
}
test() === window;  //true

Если вы запустите ту же тестовую функцию в строгом режиме, для нее будет установлено значение undefined.

function test(){
   'use strict'; 
   console.log(this);  //undefined
   return this;
}
test() === window;  //false

Причина, по которой она возвращает undefined, заключается в том, что функция была вызвана напрямую, а не как свойство объекта, в данном случае объекта window.
Поскольку он выполняется в строгом режиме, вам нужно, чтобы объект, для которого вызывается метод, был точно сопоставлен с контекстом (this). Таким образом, хотя test() === windowможет вернуть false, window.test() == window вернет true.

3. «это» внутри класса

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

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

Причина, по которой я включил здесь этот пример функционального класса, а не правильный класс, заключается в том, что когда вы вызываете эту функцию с ключевым словом new и без него, значение this изменяется. В случае класса вы не можете запустить его без ключевого слова new. Движок JS выдаст ошибку.

function Employee(name) {
    this.name = name;
}  //implicitly returns the object instance if called with the new keyword
let e1 = new Employee("Abcd");   //{ name : "Abcd" }

Если вы вызываете функцию Employee без ключевого слова new, значение this не будет экземпляром класса. Вместо этого он устанавливает значение this по умолчанию, то есть объект window.

function Employee(name) {
    this.name = name;
}  //implicitly return the object instance if called with the new keyword
let e1 = Employee("Abcd");  //undefined because the function only implicitly returns an object if called with the new keyword

Вы можете убедиться, что this относится к объекту окна, просто найдя свойство name в объекте окна.

4. «это» внутри стрелочных функций

Ключевое слово this внутри стрелочных функций относится к лексической области видимости, содержащей функцию. Поэтому, если вы создаете стрелочные функции в глобальной области видимости, this всегда будет устанавливаться на глобальный объект (окно).

//Global scope 
let global = this  //window object inside this variable
var foo = () => this;
foo() == global //true   

Если вы посмотрите на приведенный ниже пример, у нас есть функция стрелки как метод внутри объекта. Теперь, когда этот метод пытается найти this.model, значение this ищет объемлющую лексическую область, которая в данном случае является глобальной областью. Таким образом, он устанавливает значение this для объекта окна. Он также возвращает неопределенное значение, поскольку к объекту окна не прикреплено свойство model.

const car = {
  model : "BMW",
  start : () => console.log(`${this.model} go brrr`)
}
car.start()  //undefined go brrr

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

const car = {
  model : "BMW",
  start(){
   const f = () => console.log(`${this.model} go brrr`);
   f();
  } 
}
car.start()  //BMW go brrr

Поэтому, когда вы вызываете свою стрелочную функцию, она будет смотреть на лексическую область видимости своего родителя, которая в данном случае является методом запуска, и, поскольку контекст метода запуска указывает на объект автомобиля, ваш метод вернет ожидаемое значение для this.model.

Заключение

В первую очередь это подводит итог тому, как this работает в JavaScript. Как видите, это не просто ссылка на экземпляр класса, как в случае, скажем, с Java. Это не одна из тех тем, в которых сразу не разберешься. Попробуйте поэкспериментировать с ним в разных сценариях, чтобы лучше усвоить его.

Если вы лучше учитесь, просматривая видео, у меня есть видеоверсия этой записи в блоге, которую вы можете посмотреть. на ютубе.

Если у вас есть другие сомнения или предложения, вы можете изложить их в комментариях или связаться со мной в любой из моих социальных сетей. Ваше здоровье!

YouTube
LinkedIn
Twitter
GitHub

Дополнительные материалы на PlainEnglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter и LinkedIn. Присоединяйтесь к нашему сообществу Discord.