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

Есть ли собственный this у стрелочной функции?

1.0 Junior🔥 251 комментариев
#JavaScript Core

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

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

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

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

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

Различие между обычной функцией и стрелочной

Обычная функция (имеет собственный this)

const person = {
  name: 'Alice',
  sayName: function() {
    console.log(this.name); // this зависит от того, как вызвана функция
  }
};

person.sayName(); // 'Alice' (this === person)

const sayName = person.sayName;
sayName(); // undefined (this === window или undefined в strict mode)
// this потеряется при передаче функции

const boundSayName = person.sayName.bind(person);
boundSayName(); // 'Alice' (bind установил this)

Стрелочная функция (наследует this)

const person = {
  name: 'Bob',
  sayName: () => {
    // this наследуется из окружающего контекста
    // Окружающий контекст = global object (window)
    console.log(this.name); // undefined (this === window)
  }
};

person.sayName(); // undefined (НЕ Bob!)
// В стрелочной функции this НЕ меняется при вызове

// Правильно для методов объекта:
const person2 = {
  name: 'Bob',
  sayName() { // Используй обычный метод
    console.log(this.name); // 'Bob'
  }
};

person2.sayName(); // 'Bob'

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

Правило: Lexical This

// this в стрелочной функции = this в окружающем scope

const obj = {
  value: 42,
  createArrow: function() {
    // В этом месте this === obj
    return () => {
      // Стрелочная функция наследует this === obj
      console.log(this.value);
    };
  }
};

const arrow = obj.createArrow();
arrow(); // 42 (this всё ещё obj, даже вне методе)

// Сравни с обычной функцией:
const obj2 = {
  value: 42,
  createFunc: function() {
    return function() {
      console.log(this.value); // undefined (this потеряется)
    };
  }
};

const func = obj2.createFunc();
func(); // undefined

Вложенные контексты

const app = {
  title: 'MyApp',
  users: ['Alice', 'Bob'],
  
  // Обычный метод
  showUsers: function() {
    console.log(this.title); // 'MyApp' (this === app)
    
    // Обычная функция в callback-е
    this.users.forEach(function(user) {
      console.log(user, this.title); 
      // undefined undefined (потеря this)
    });
    
    // Стрелочная функция в callback-е
    this.users.forEach(user => {
      console.log(user, this.title);
      // 'Alice MyApp', 'Bob MyApp' (наследует this из showUsers)
    });
  }
};

app.showUsers();
// Классическая проблема: потеря this при передаче callback-ов
// Решение: стрелочные функции!

Практические примеры

1. Обработчики событий в React

class Button extends React.Component {
  constructor(props) {
    super(props);
    this.state = { clicked: false };
  }

  // БЕЗ стрелочной функции нужен bind
  handleClickBad() {
    // this будет undefined, если не забиндить
    this.setState({ clicked: true });
  }

  // Решение 1: bind в конструкторе
  constructor(props) {
    super(props);
    this.handleClickGood = this.handleClickGood.bind(this);
  }
  handleClickGood() {
    this.setState({ clicked: true });
  }

  // Решение 2: class field со стрелочной (РЕКОМЕНДУЕТСЯ)
  handleClickBest = () => {
    // this наследуется из класса, всегда работает
    this.setState({ clicked: true });
  };

  render() {
    return (
      <button onClick={this.handleClickBest}>
        Click me
      </button>
    );
  }
}

2. Асинхронные операции

const api = {
  baseURL: 'https://api.example.com',
  
  // БЕЗ стрелочной функции
  fetchDataBad: function(id) {
    fetch(`${this.baseURL}/users/${id}`)
      .then(function(response) {
        // this потеряется
        return response.json();
      })
      .then(function(data) {
        console.log(this.baseURL); // undefined!
      });
  },
  
  // СО стрелочной функцией
  fetchDataGood: function(id) {
    fetch(`${this.baseURL}/users/${id}`)
      .then(response => response.json())
      .then(data => {
        console.log(this.baseURL); // 'https://api.example.com'
      });
  }
};

api.fetchDataGood(1); // Работает!

3. setTimeout и this

const timer = {
  seconds: 0,
  
  // БЕЗ стрелочной функции
  startBad: function() {
    setInterval(function() {
      console.log(this.seconds++); // undefined, this потеряется
    }, 1000);
  },
  
  // СО стрелочной функцией
  startGood: function() {
    setInterval(() => {
      console.log(this.seconds++); // Работает!
    }, 1000);
  }
};

timer.startGood();
// 0
// 1
// 2
// ...

call(), apply(), bind() с стрелочными функциями

const person = {
  name: 'Alice'
};

const regular = function() {
  console.log(this.name);
};

const arrow = () => {
  console.log(this.name);
};

// call() и apply() РАБОТАЮТ для обычных функций
regular.call(person); // 'Alice'
regular.apply(person); // 'Alice'

// call() и apply() НЕ РАБОТАЮТ для стрелочных!
const globalName = 'Global';
arrow.call(person); // 'Global' (игнорирует person)
arrow.apply(person); // 'Global' (игнорирует person)

// bind() работает, но не меняет this
const boundArrow = arrow.bind(person);
boundArrow(); // 'Global' (bind не поможет)

// this в стрелочной функции зафиксирована на момент определения
// и её нельзя изменить никакими методами

Когда НЕ использовать стрелочные функции

1. Методы объектов

// Плохо
const calculator = {
  value: 0,
  add: (n) => {
    this.value += n; // this не будет калькулятором
    return this.value; // undefined
  }
};

calculator.add(5); // undefined

// Хорошо
const calculator = {
  value: 0,
  add(n) {
    this.value += n;
    return this.value;
  }
};

calculator.add(5); // 5

2. Конструкторы

// Плохо: стрелочные функции не могут быть конструкторами
const User = (name) => {
  this.name = name;
};

const user = new User('Alice'); // TypeError!

// Хорошо
class User {
  constructor(name) {
    this.name = name;
  }
}

const user = new User('Alice'); // OK

3. Динамический this

// Если нужен динамический this
const obj = {
  value: 1,
  getValue: function() {
    // this зависит от того, как вызвана функция
    return this.value;
  }
};

obj.getValue(); // 1

const getValue = obj.getValue;
getValue.call({ value: 100 }); // 100 (можем изменить this)

// Со стрелочной это невозможно

4. prototype и this

// Плохо
const MyClass = function() {
  this.value = 1;
};

MyClass.prototype.increment = () => {
  this.value++; // this будет global, не экземпляр
};

const instance = new MyClass();
instance.increment(); // this.value остаётся 1

// Хорошо
MyClass.prototype.increment = function() {
  this.value++; // this === instance
};

instance.increment(); // this.value === 2

Современный подход: класс + стрелочные

class TodoList {
  items: string[] = [];

  // Обычный метод
  addItem(item: string) {
    this.items.push(item);
  }

  // Class field со стрелочной для callback-ов
  handleClick = (id: number) => {
    console.log('clicked', id);
    // this всегда будет экземпляром TodoList
  };

  // Использование в React
  render() {
    return (
      <div>
        {this.items.map((item, i) => (
          // this.handleClick уже забинден правильно
          <button key={i} onClick={this.handleClick}>
            {item}
          </button>
        ))}
      </div>
    );
  }
}

Хитрости с this

// Проверить значение this
function whatIsThis() {
  console.log(this);
}

whatIsThis(); // window (или undefined в strict mode)

whatIsThis.call({ custom: 'object' }); // { custom: 'object' }

// Стрелочная всегда показывает глобальный контекст
const arrowThis = () => {
  console.log(this); // window всегда
};

arrow.call({ custom: 'object' }); // window (игнорирует call)

// Проверить, есть ли собственный this
console.log(whatIsThis.hasOwnProperty('this')); // false
// this — это не свойство, это ключевое слово

Итог

Стрелочные функции НЕ имеют собственного this:

  • Lexical this — наследуют из окружающего контекста
  • Нельзя изменить call(), apply(), bind()
  • Хороши для callback-ов — solve "this" binding problem
  • Плохи для методов объектов — используй обычные методы
  • Нельзя использовать как конструкторы — new стрелочная() выбросит ошибку

Практическое правило:

  • Используй стрелочные функции для callback-ов, обработчиков, map/filter
  • Используй обычные методы (function или class методы) для методов объектов
  • В классах используй class fields со стрелочными для обработчиков событий
Есть ли собственный this у стрелочной функции? | PrepBro