this - это окружающий контекст, в котором определена стрелочная функция

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

В следующем примере показана прозрачность контекста:

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
  log() {
    console.log(this === myPoint);  // => true
    setTimeout(() => {
      console.log(this === myPoint);  // => true
      console.log(this.x + ':' + this.y);  // => '95:165'
    }, 1000);
  }
}
const myPoint = new Point(95, 165);
myPoint.log();

setTimeout() вызывает стрелочную функцию с тем же контекстом (объект myPoint), что и метод log(). Как видно, стрелочная функция наследует контекст функции, в которой она определена.

Обычная функция в этом примере создаст свой собственный контекст (window или undefined). Поэтому чтобы тот же код работал правильно с выражением функции, необходимо вручную связать контекст: setTimeout(function() {...}.bind(this)). Выглядит это довольно громоздко, что делает использование стрелочной функции - более ясным и коротким решением.

Если стрелочная функция определена в самой верхней области видимости (вне любой функции), контекстом всегда является глобальный объект (window в браузере):

const getContext = () => {
 console.log(this === window);  // => true
 return this;
};
console.log(getContext() === window);   // => true

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

const numbers = [1, 2];
(function() { 
  const get = () => {
    console.log(this === numbers);  // => true
    return this;
  };
  console.log(this === numbers);  // => true
  get();  // => [1, 2]
  
  // Попытаемся вручную поменять контекст стрелочной функции
  get.call([0]);  // => [1, 2]
  get.apply([0]);  // => [1, 2]
  get.bind([0])();  // => [1, 2]
}).call(numbers);

Независимо от того, как вызывается стрелочная функция get(), она всегда сохраняет лексический контекст numbers. Непрямой вызов с другим контекстом get.call([0]) или get.apply([0]), повторное связывание get.bind([0])() не имеют никакого эффекта.

Стрелочную функцию нельзя использовать в качестве конструктора. Вызов ее как конструктора new get() вызовет ошибку  TypeError.