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

Как работает This?

1.3 Junior🔥 191 комментариев
#JavaScript Core

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

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

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

This в JavaScript: полное объяснение механизма

this — динамическое значение, которое вычисляется при вызове функции, а не при её определении. Это источник большинства ошибок у начинающих разработчиков.

Основное правило

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

5 основных правил определения This

1. Глобальный контекст

function getName() {
  console.log(this);
}

getName();  // this === window (в браузере) или global (в Node.js)

// В strict mode
'use strict';
function getName() {
  console.log(this);  // undefined
}

2. Метод объекта (Object Method)

const user = {
  name: 'Alice',
  getName() {
    console.log(this.name);
  }
};

user.getName();  // this === user → "Alice"

// Но если присвоить методу переменную
const fn = user.getName;
fn();  // this === window → undefined (потеря контекста!)

3. call, apply, bind (явное связывание)

function greet(greeting) {
  console.log(`${greeting}, ${this.name}`);
}

const user = { name: 'Bob' };

// call — вызови с явным this
greet.call(user, 'Hello');  // this === user → "Hello, Bob"

// apply — то же, но args в массиве
greet.apply(user, ['Hi']);  // "Hi, Bob"

// bind — создай функцию с привязанным this
const boundGreet = greet.bind(user);
boundGreet('Hey');  // "Hey, Bob"
boundGreet('Yo');   // "Yo, Bob" — this всегда user

4. new (конструктор)

function User(name) {
  this.name = name;  // this — новый объект
}

const alice = new User('Alice');
console.log(alice.name);  // "Alice"

5. Стрелочные функции (Arrow Functions)

// Стрелочные функции НЕ имеют собственного this
// Они наследуют this из окружающей области видимости (lexical this)

const user = {
  name: 'Charlie',
  
  // Обычная функция
  greet() {
    console.log(this.name);  // "Charlie"
  },
  
  // Стрелочная функция — наследует this с уровня выше
  greetArrow: () => {
    console.log(this.name);  // undefined (this из глобального уровня)
  },
  
  // Стрелочная внутри метода — наследует this из метода
  delayedGreet() {
    setTimeout(() => {
      console.log(this.name);  // "Charlie" (наследует из delayedGreet)
    }, 1000);
  }
};

user.greet();         // "Charlie"
user.greetArrow();    // undefined
user.delayedGreet();  // "Charlie" (через 1 сек)

Приоритет правил

Когда несколько правил применяются одновременно:

  1. Стрелочная функция → наследует из контекста
  2. bind/call/apply → явное связывание (самый высокий приоритет!)
  3. new → конструктор
  4. Метод объекта → this === объект
  5. Глобальный контекст → window/global/undefined
const user = { name: 'Alice' };

function getName() {
  console.log(this.name);
}

// Bind имеет приоритет над методом объекта
const boundGetName = getName.bind({ name: 'Bob' });
const obj = { getName: boundGetName };

obj.getName();  // "Bob" (bind выиграл!), не "Alice"

Частые ошибки

Ошибка 1: Потеря контекста в callbacks

class Counter {
  count = 0;
  
  increment() {
    this.count++;  // this === Counter
  }
  
  // Плохо — this потеряется
  start() {
    setInterval(this.increment, 1000);
    // this.increment вызовется как функция, не метод!
  }
  
  // Хорошо — используй стрелочную функцию
  start() {
    setInterval(() => this.increment(), 1000);
    // Стрелочная функция наследует this из start
  }
  
  // Хорошо — используй bind
  start() {
    setInterval(this.increment.bind(this), 1000);
  }
}

Ошибка 2: This в React классе

// Плохо
class Button extends React.Component {
  handleClick() {
    console.log(this.props);  // undefined!
  }
  render() {
    return <button onClick={this.handleClick}>Click</button>;
  }
}

// Хорошо 1 — bind в конструкторе
class Button extends React.Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    console.log(this.props);
  }
  render() {
    return <button onClick={this.handleClick}>Click</button>;
  }
}

// Хорошо 2 — стрелочная функция (modern way)
class Button extends React.Component {
  handleClick = () => {
    console.log(this.props);
  }
  render() {
    return <button onClick={this.handleClick}>Click</button>;
  }
}

Практический пример: Event Listener

const button = document.querySelector('button');
const handler = {
  clicks: 0,
  
  // Плохо — this будет button, не handler
  onClick() {
    this.clicks++;  // this === button!
    console.log(this.clicks);  // undefined
  }
};

button.addEventListener('click', handler.onClick);  // Ошибка!

// Решение 1: используй bind
button.addEventListener('click', handler.onClick.bind(handler));

// Решение 2: стрелочная функция
button.addEventListener('click', () => handler.onClick());

Таблица значений This

КонтекстThis указывает наПример
Обычная функцияwindow/global/undefinedfunc()
Метод объектаобъектobj.method()
call/applyпервый аргументfn.call(obj)
bindпривязанный объектfn.bind(obj)()
newновый объектnew Constructor()
Стрелочнаяиз контекста() => {}
Event listenerэлементel.addEventListener('click', fn)

Совет для отладки

Используй console.log в разных местах:

function debug() {
  console.log('this:', this);
  console.log('this.name:', this?.name);
}

const user = { name: 'Alice' };
user.debug = debug;

user.debug();  // this === user
debug();       // this === window (или undefined в strict)

Финальный совет

В современном JavaScript стрелочные функции решили большинство проблем с this. Но понимание механизма — критично для интервью и работы с legacy кодом.

Знай все 5 правил, приоритеты, и ты сможешь объяснить любой баг связанный с контекстом!