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

Почему при вызове this в стрелочной функции выводится контекст родителя?

2.0 Middle🔥 211 комментариев
#JavaScript Core

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

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

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

this в стрелочных функциях

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

Как работает this в обычных функциях

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

const user = {
  name: "Alice",
  greet: function() {
    console.log(this.name); // this определяется при вызове
  }
};

user.greet(); // Выводит: Alice (this = user)

const greetFunc = user.greet;
greetFunc(); // Выводит: undefined (this = global object или undefined в strict mode)

Когда функция вызывается как метод объекта, this указывает на этот объект. Когда функция вызывается отдельно, this указывает на глобальный объект (в браузере — window, в Node.js — global).

Стрелочные функции наследуют this из родителя

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

const user = {
  name: "Alice",
  age: 25,
  greet: function() {
    // обычная функция имеет свой this
    console.log("Regular function this:", this); // {name: "Alice", age: 25, greet: ...}
  },
  sayName: () => {
    // стрелочная функция наследует this из окружения
    console.log("Arrow function this:", this); // window или global (не user!)
  }
};

user.greet();  // this = user объект
user.sayName(); // this = window (глобальный объект)

Практический пример: обработчики событий

Одна из самых распространённых проблем — использование обычных функций в обработчиках событий:

class Counter {
  constructor() {
    this.count = 0;
    this.button = document.querySelector("button");
  }

  init() {
    // ❌ Неправильно: обычная функция теряет контекст
    this.button.addEventListener("click", function() {
      this.count++; // this = button элемент, не Counter!
      console.log(this.count); // undefined
    });

    // ✅ Правильно: стрелочная функция сохраняет контекст
    this.button.addEventListener("click", () => {
      this.count++; // this = Counter экземпляр
      console.log(this.count); // работает!
    });
  }
}

Почему стрелочные функции наследуют this

Причина 1: Лексическое связывание

Стрелочные функции привязаны к this на момент определения функции, не на момент её вызова:

const obj = {
  name: "Alice",
  createArrow: function() {
    // Стрелочная функция захватывает this из createArrow (обычная функция)
    const arrow = () => {
      console.log(this.name); // this из createArrow = obj
    };
    return arrow;
  }
};

const arrowFunc = obj.createArrow();
arrowFunc(); // Выводит: Alice

// Даже если вызвать на другом объекте
const other = { name: "Bob" };
arrowFunc.call(other); // Всё равно выводит: Alice (this нельзя изменить!)

Причина 2: Предсказуемость в классах

В классах стрелочные функции как поля автоматически получают контекст:

class Timer {
  delay = 1000;

  // ❌ Неправильно: потеря контекста
  tick() {
    setTimeout(function() {
      console.log(this); // undefined или window
    }, this.delay);
  }

  // ✅ Правильно: стрелочная функция
  tickCorrect() {
    setTimeout(() => {
      console.log(this); // Timer экземпляр
    }, this.delay);
  }

  // ✅ Альтернатива: привязание вручную
  tickBind() {
    setTimeout(function() {
      console.log(this); // Timer экземпляр (через .bind())
    }.bind(this), this.delay);
  }
}

Сравнение способов сохранения контекста

const user = {
  name: "Alice",
  greet: function() {
    setTimeout(function() {
      console.log(this.name); // undefined (потеря контекста)
    }, 100);
  },
  greetCorrect1: function() {
    // Способ 1: Стрелочная функция (современный способ)
    setTimeout(() => {
      console.log(this.name); // Alice
    }, 100);
  },
  greetCorrect2: function() {
    // Способ 2: Сохранить this в переменную
    const self = this;
    setTimeout(function() {
      console.log(self.name); // Alice
    }, 100);
  },
  greetCorrect3: function() {
    // Способ 3: bind()
    setTimeout(function() {
      console.log(this.name); // Alice
    }.bind(this), 100);
  }
};

В React компонентах

В современных React компонентах (функциональные компоненты с хуками) эта проблема актуальна:

function UserProfile() {
  const [user, setUser] = useState(null);

  // ✅ Правильно: стрелочная функция в useCallback
  const handleFetch = useCallback(() => {
    fetch("/api/user")
      .then((res) => res.json())
      .then((data) => setUser(data)); // setUser из замыкания
  }, []);

  return (
    <button onClick={handleFetch}>Загрузить профиль</button>
  );
}

Важные моменты

  • Стрелочные функции не имеют собственного this — они наследуют его из окружающей области
  • this привязана на момент определения, не на момент вызова
  • Методы call(), apply() и bind() не могут переопределить this в стрелочной функции
  • В классах как методы обычные функции теряют контекст, но как поля-стрелки сохраняют

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

Почему при вызове this в стрелочной функции выводится контекст родителя? | PrepBro