← Назад к вопросам

Как при написании this понимаешь что будет нужный объект?

2.3 Middle🔥 275 комментариев
#JavaScript Core

Комментарии (5)

🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Определение значения this в JavaScript

Одна из самых сложных частей JavaScript — понимание, на что указывает this в каждый момент времени. Это зависит от того, как функция вызвана, а не где она определена.

Правило 1: Правило вызова (Call Site Rule)

Главное правило: смотри, ГДЕ вызвана функция, а не где она определена. this определяется в момент вызова.

// Объект
const obj = {
  name: "Alice",
  greet: function() {
    console.log(this.name); // this указывает на obj
  }
};

obj.greet(); // Вывод: Alice
// Почему: функция вызвана как obj.greet(), this = obj

// Но если присваиваешь функцию переменной...
const greetFn = obj.greet;
greetFn(); // Вывод: undefined
// Почему: функция вызвана как greetFn(), this = window (или undefined в strict mode)
// Потеря контекста!

Правило 2: Неявный контекст (Implicit Binding)

Когда функция вызывается как метод объекта, this указывает на этот объект.

const user = {
  name: "Bob",
  age: 25,
  displayInfo: function() {
    console.log(this.name, this.age);
  }
};

user.displayInfo(); // this = user
// Вывод: Bob 25

// Но если вложить функцию...
const user2 = {
  name: "Carol",
  details: {
    info: function() {
      console.log(this.name); // this = details объект, не user2
    }
  }
};

user2.details.info(); // this указывает на details, не user2
// Вывод: undefined (у details объекта нет name)

Правило 3: Явный контекст (Explicit Binding)

Используй call(), apply(), bind() для явного указания this.

function introduce() {
  console.log("Меня зовут " + this.name);
}

const person1 = { name: "Dave" };
const person2 = { name: "Eve" };

// call() — вызвать с явным this
introduce.call(person1); // Вывод: Меня зовут Dave
introduce.call(person2); // Вывод: Меня зовут Eve

// apply() — как call, но аргументы в массиве
function greetWithAge(age) {
  console.log(this.name + " возраст " + age);
}

greetWithAge.apply(person1, [30]); // Вывод: Dave возраст 30

// bind() — создаёт новую функцию с привязанным this
const boundGreet = introduce.bind(person1);
boundGreet(); // Вывод: Меня зовут Dave
boundGreet(); // Можно вызывать много раз

// Полезно для обработчиков событий
class Button {
  constructor(label) {
    this.label = label;
    // Привязываем this раз при конструировании
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    console.log(this.label + " нажата");
  }

  render() {
    return <button onClick={this.handleClick}>{this.label}</button>;
  }
}

Правило 4: Стрелочные функции (Arrow Functions)

Стрелочные функции НЕ имеют своего this. Они берут this из внешней области видимости.

// Обычная функция
const obj1 = {
  name: "Frank",
  regularFunction: function() {
    console.log(this.name); // this = obj1
  },
  arrowFunction: () => {
    console.log(this.name); // this = window (или undefined)
  }
};

obj1.regularFunction(); // Вывод: Frank
obj1.arrowFunction(); // Вывод: undefined

// В методе с регулярной функцией стрелочная берёт this из метода
const obj2 = {
  name: "Grace",
  outerMethod: function() {
    console.log("Outer:", this.name); // this = obj2

    const innerArrow = () => {
      console.log("Inner:", this.name); // this = obj2 (из outerMethod)
    };

    innerArrow(); // Вывод: Inner: Grace
  }
};

obj2.outerMethod();

// Стрелочная функция НЕ подходит для методов объекта
const obj3 = {
  name: "Henry",
  greet: () => {
    console.log(this.name); // НЕПРАВИЛЬНО! this = window
  }
};

obj3.greet(); // Вывод: undefined

Правило 5: Конструктор (Constructor)

Когда функция вызвана с new, this указывает на новый объект.

function User(name) {
  this.name = name;
  this.greet = function() {
    console.log("Привет, " + this.name);
  };
}

const user1 = new User("Ivan");
user1.greet(); // Вывод: Привет, Ivan
// this = user1

// Класс (ES6) — это синтаксический сахар для конструктора
class Person {
  constructor(name) {
    this.name = name; // this = создаваемый объект
  }

  greet() {
    console.log("Привет, " + this.name);
  }
}

const person = new Person("Julia");
person.greet(); // Вывод: Привет, Julia

Как я определяю this на практике

// ТЕХНИКА: Следи по цепочке вызовов

// Пример 1: Простой вызов
function test() {
  console.log(this);
}

test(); // this = undefined (strict mode) или window

// Пример 2: Метод объекта
const obj = { test: test };
obj.test(); // this = obj

// Пример 3: setTimeout с обычной функцией
const obj2 = {
  name: "Kevin",
  delay: function() {
    setTimeout(function() {
      console.log(this.name); // this = window, потеря контекста
    }, 100);
  }
};

obj2.delay(); // Вывод: undefined

// Исправление 1: Стрелочная функция
const obj3 = {
  name: "Laura",
  delay: function() {
    setTimeout(() => {
      console.log(this.name); // this = obj3
    }, 100);
  }
};

obj3.delay(); // Вывод: Laura

// Исправление 2: bind
const obj4 = {
  name: "Mike",
  delay: function() {
    setTimeout(function() {
      console.log(this.name); // this = obj4 (благодаря bind)
    }.bind(this), 100);
  }
};

obj4.delay(); // Вывод: Mike

Практическое правило для быстрого определения

Когда видишь this, спроси себя:

  1. Это стрелочная функция? — Используй this из внешней области
  2. Есть точка перед функцией (obj.method)? — this = obj
  3. Есть call(), apply() или bind()? — this = первый аргумент
  4. Есть new? — this = новый объект
  5. Иначе — this = window (или undefined в strict mode)

Итого

Определение this:

  1. Неявный — через точку (obj.method -> this = obj)
  2. Явный — call(), apply(), bind()
  3. Стрелочные — берут this из внешней области
  4. Конструктор — new создаёт this
  5. По умолчанию — window или undefined

Главное: смотри на МЕСТО ВЫЗОВА, не на место определения.

Как при написании this понимаешь что будет нужный объект? | PrepBro