Не могу понять как работает контекст в стрелочных функциях ES6

Я читал много статей про стрелочные функции в JavaScript, но все еще путаюсь с тем как работает контекст.

Что я понимаю:

  • В обычных функциях this зависит от того, кто вызывает функцию.
  • В стрелочных функциях this берется из окружающего контекста.

Мои вопросы:

  1. Что точно означает “окружающий контекст”? Достаточно ли фигурных скобок {} чтобы создать такой контекст?

  2. Пример с EventEmitter:

const { EventEmitter } = require('events');

class User extends EventEmitter {
  constructor(username) {
    super();
    this.username = username;
  }
}

let john = new User('john');
john.on('message', (text) => {
  console.log(`${this.username}: ${text}`);
});
john.emit('message', 'привет всем');

Почему стрелочная функция тут не работает? Объект john вызывает метод on, так почему стрелочная функция не может получить this из контекста метода on?

  1. С обычной функцией все работает:
john.on('message', function(text) {
  console.log(this.username); // работает
});

Но почему? Ведь john вызывает on, а не саму анонимную функцию внутри.

  1. Если стрелочная функция передается как параметр someFunc(() => {}), что считается ее окружающим контекстом?

Заранее спасибо за помощь!

Стрелочная функция “заморозила” this еще при написании кода. Окружающий контекст - это где именно ты пишешь функцию, не просто фигурные скобки. В твоем примере стрелочная функция на верхнем уровне скрипта, поэтому this = undefined. Обычная функция получает this от EventEmitter’а когда событие срабатывает. В колбэках почти всегда нужны обычные функции, если хочешь получить контекст от вызывающего.

А ты смотрел в консоли браузера, что там выводится, когда стрелочная функция глючит? Наверняка undefined вместо имени? Стрелочные функции берут this оттуда, где они написаны, а не где вызываются. У тебя это скорее всего глобальный контекст.

Стрелочная функция “запоминает” this в момент создания, а не вызова. Твой колбэк создается в глобальной области, поэтому this = undefined (или window в браузере). Обычная функция берет this от того, кто её вызывает - здесь от EventEmitter’а. Поэтому с колбэками работает только обычная функция.