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

В чем разница между записью стрелочной и именованной функции в поле класса?

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

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

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

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

В чем разница между записью стрелочной и именованной функции в поле класса

Контекст вопроса

Вопрос относится к классам в JavaScript и особенностям bind контекста this.

1. Именованная функция (метод класса)

Синтаксис

class User {
  name = 'John';
  
  // Именованная функция (метод)
  greet() {
    console.log(`Hello, ${this.name}`);
  }
}

const user = new User();
user.greet();  // 'Hello, John'

// Проблема: `this` может быть потерян
const greet = user.greet;
greet();  // undefined (this === undefined в strict mode)

Где хранится

class User {
  greet() { }  // В prototype!
}

const user1 = new User();
const user2 = new User();

console.log(user1.greet === user2.greet);  // true!
// Метод существует один раз в User.prototype

console.log(user1.hasOwnProperty('greet'));  // false
console.log(User.prototype.hasOwnProperty('greet'));  // true

Преимущества:

  • Экономия памяти (один раз в prototype)
  • Это стандартный OOP подход
  • Можно переопределить в наследниках

Недостатки:

  • this не автоматически bound
  • Нужно использовать .bind() при передаче callbacks

2. Стрелочная функция в поле класса

Синтаксис

class User {
  name = 'John';
  
  // Стрелочная функция как поле класса
  greet = () => {
    console.log(`Hello, ${this.name}`);
  };
}

const user = new User();
user.greet();  // 'Hello, John'

// Это работает!
const greet = user.greet;
greet();  // 'Hello, John' (this === user!)

Где хранится

class User {
  greet = () => { };
}

const user1 = new User();
const user2 = new User();

console.log(user1.greet === user2.greet);  // false!
// Каждый объект имеет СВОЮ копию функции

console.log(user1.hasOwnProperty('greet'));  // true
console.log(User.prototype.hasOwnProperty('greet'));  // false

Преимущества:

  • this всегда bound к объекту
  • Удобно для callbacks
  • Работает при деструктуризации

Недостатки:

  • Больше памяти (копия для каждого объекта)
  • Нельзя переопределить в наследниках
  • Медленнее при создании объектов

Практическое сравнение

Сценарий 1: Передача как callback

class Button {
  label = 'Click me';
  
  // Именованная функция
  handleClickMethod() {
    console.log(this.label);
  }
  
  // Стрелочная функция
  handleClickArrow = () => {
    console.log(this.label);
  };
}

const button = new Button();

// Прямой вызов работает в обоих случаях
button.handleClickMethod();  // 'Click me'
button.handleClickArrow();   // 'Click me'

// Но как callback:
setTimeout(button.handleClickMethod, 1000);  // undefined
setTimeout(button.handleClickArrow, 1000);   // 'Click me'

// Или в обработчике события
document.addEventListener('click', button.handleClickMethod);  // undefined
document.addEventListener('click', button.handleClickArrow);   // 'Click me'

Сценарий 2: Наследование

class Animal {
  name = 'Animal';
  
  // Именованная функция
  sayMethod() {
    console.log(`${this.name} says!`);
  }
  
  // Стрелочная функция
  sayArrow = () => {
    console.log(`${this.name} says!`);
  };
}

class Dog extends Animal {
  name = 'Dog';
  
  // Можем переопределить метод
  sayMethod() {
    console.log(`${this.name} barks!`);
  }
  
  // Нельзя переопределить стрелочную функцию
  // sayArrow = () => { }  // Нужно полностью переписать
}

const dog = new Dog();
dog.sayMethod();   // 'Dog barks!' (переопределена)
dog.sayArrow();    // 'Dog says!' (родительская, потому что this bound)

Сценарий 3: Использование в React (функциональные компоненты)

// Современный способ в React (функциональные компоненты)
function Counter() {
  const [count, setCount] = useState(0);
  
  // Стрелочная функция инлайн
  const handleClick = () => {
    setCount(count + 1);
  };
  
  return <button onClick={handleClick}>{count}</button>;
}

// Старый способ с классами
class Counter extends React.Component {
  state = { count: 0 };
  
  // Вариант 1: Методы со .bind()
  handleClickMethod() {
    this.setState({ count: this.state.count + 1 });
  }
  constructor(props) {
    super(props);
    this.handleClickMethod = this.handleClickMethod.bind(this);
  }
  
  // Вариант 2: Стрелочная функция (проще!)
  handleClickArrow = () => {
    this.setState({ count: this.state.count + 1 });
  };
  
  render() {
    return <button onClick={this.handleClickArrow}>{this.state.count}</button>;
  }
}

Производительность

Создание объектов

// Именованная функция (быстро)
class UserMethod {
  getName() { return this.name; }
}

// Стрелочная функция (медленнее)
class UserArrow {
  getName = () => this.name;
}

// Тест создания 100,000 объектов
console.time('method');
for (let i = 0; i < 100000; i++) new UserMethod();
console.timeEnd('method');  // ~5ms

console.time('arrow');
for (let i = 0; i < 100000; i++) new UserArrow();
console.timeEnd('arrow');   // ~15ms (медленнее)

Использование памяти

// 1000 объектов с методами
const methods = Array.from({length: 1000}, () => new UserMethod());
// Потребление памяти: ~1 KB (все используют функцию из prototype)

const arrows = Array.from({length: 1000}, () => new UserArrow());
// Потребление памяти: ~50 KB (каждый объект имеет свою копию функции)

Таблица сравнения

АспектИменованная функцияСтрелочная функция
Синтаксисmethod() {}method = () => {}
Контекст thisНужно bindАвтоматически bound
ПамятьЭкономно (prototype)Больше (копия в каждом объекте)
Скорость созданияБыстроМедленнее
CallbacksНужно .bind()Работает сразу
НаследованиеПереопределяемоСложнее переопределить
OOP практикаСтандартноСовременно

Рекомендации

Используй методы (именованные функции) для:

class Model {
  // Обычные методы
  load() { }
  save() { }
  delete() { }
}

Используй стрелочные функции для:

class Component {
  // Обработчики событий
  handleClick = () => { };
  handleChange = () => { };
  
  // Callbacks для async операций
  onSuccess = (data) => { };
  onError = (error) => { };
}

Или лучше используй функциональные компоненты React:

// Вместо классов
function MyComponent() {
  const handleClick = () => { };  // Все стрелочные
  const handleChange = () => { };
  
  return <div onClick={handleClick} />;
}

Заключение

Основная разница:

  • Именованная функция в методе: это функция в prototype, this зависит от контекста вызова
  • Стрелочная функция в поле класса: это свойство объекта, this всегда bound к объекту

На практике:

  • Если нужно передать обработчик как callback — используй стрелочную
  • Если это обычный метод класса — используй именованную
  • Но лучше вообще используй функциональные компоненты в React, а не классы
В чем разница между записью стрелочной и именованной функции в поле класса? | PrepBro