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

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

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

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

🐱
claude-haiku-4.5PrepBro AI21 мар. 2026 г.(ред.)

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

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

Обычные функции (Function Declaration и Function Expression) и стрелочные функции (Arrow Functions) имеют фундаментальные различия в поведении. Это не просто синтаксис - это разные типы функций с разными свойствами.

1. Использование как конструктор (new)

Обычная функция может быть конструктором:

// ✅ Обычная функция - можно использовать с new
function Person(name) {
  this.name = name;
  this.greet = function() {
    console.log(`Hi, I'm ${this.name}`);
  };
}

const john = new Person('John'); // Работает!
john.greet(); // 'Hi, I'm John'

// ❌ Стрелочная функция - НЕЛЬЗЯ использовать с new
const PersonArrow = (name) => {
  this.name = name; // this будет undefined
};

const mary = new PersonArrow('Mary'); // TypeError: PersonArrow is not a constructor

Почему? Обычная функция создает свой объект this и имеет prototype. Стрелочная функция этого не имеет.

2. Собственное значение this

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

// ✅ Обычная функция - this зависит от context
const obj = {
  name: 'Object',
  sayName: function() {
    console.log(this.name); // this = obj
  },
  delayedSayName: function() {
    setTimeout(function() {
      console.log(this); // this = window (в браузере) или undefined (strict mode)
    }, 1000);
  }
};

obj.sayName(); // 'Object'
obj.delayedSayName(); // undefined (потеряли контекст!)

Стрелочная функция наследует this из внешней области видимости:

// ✅ Стрелочная функция - наследует this
const obj = {
  name: 'Object',
  delayedSayName: function() {
    setTimeout(() => {
      console.log(this.name); // this = obj (правильно!)
    }, 1000);
  }
};

obj.delayedSayName(); // 'Object' через 1 сек

// ❌ Стрелочная как метод объекта - this не то
const obj2 = {
  name: 'Object2',
  sayName: () => {
    console.log(this.name); // this = window, не obj2
  }
};

obj2.sayName(); // undefined

Лучшая практика: Используй стрелочные функции для callback-ов, обычные - для методов объектов.

3. Свойство prototype

Обычная функция имеет prototype:

// ✅ Обычная функция
function Dog() {}
Dog.prototype.bark = function() {
  console.log('Woof!');
};

const dog = new Dog();
dog.bark(); // 'Woof!' - найдет в prototype
console.log(Dog.prototype); // { bark: [Function] }

// ❌ Стрелочная функция - нет prototype
const Cat = () => {};
console.log(Cat.prototype); // undefined
const cat = new Cat(); // TypeError

4. Свойство arguments

Обычная функция имеет объект arguments:

// ✅ Обычная функция - arguments существует
function sum() {
  console.log(arguments); // Arguments(3) [1, 2, 3]
  return arguments[0] + arguments[1] + arguments[2];
}

sum(1, 2, 3); // 6

// ❌ Стрелочная функция - arguments нет
const sumArrow = () => {
  console.log(arguments); // ReferenceError: arguments is not defined
};

// Но можно использовать rest parameters
const sumArrow2 = (...args) => {
  console.log(args); // [1, 2, 3]
  return args.reduce((a, b) => a + b, 0);
};

sumArrow2(1, 2, 3); // 6

5. Hoisting (поднятие)

Function Declaration поднимается полностью:

// ✅ Можно вызвать ДО определения
greet(); // 'Hello!' - работает благодаря hoisting

function greet() {
  console.log('Hello!');
}

// ❌ Function Expression не поднимается
try {
  greetVar(); // ReferenceError: Cannot access 'greetVar' before initialization
} catch(e) {
  console.error(e);
}

const greetVar = function() {
  console.log('Hi!');
};

// ❌ Стрелочная функция тоже не поднимается
try {
  greetArrow(); // ReferenceError
} catch(e) {
  console.error(e);
}

const greetArrow = () => {
  console.log('Hey!');
};

6. Использование bind, call, apply

Обычная функция может менять this с помощью bind/call/apply:

// ✅ Обычная функция - можно изменить this
function greet(greeting) {
  console.log(`${greeting}, ${this.name}`);
}

const obj = { name: 'John' };
greet.call(obj, 'Hello'); // 'Hello, John'
greet.apply(obj, ['Hi']); // 'Hi, John'

const boundGreet = greet.bind(obj);
boundGreet('Hey'); // 'Hey, John'

// ❌ Стрелочная функция - bind/call/apply не меняют this
const greetArrow = (greeting) => {
  console.log(`${greeting}, ${this.name}`);
};

const boundArrow = greetArrow.bind(obj); // bind не сработает
boundArrow('Hello'); // 'Hello, undefined'

7. Методы bind() как обработчик событий

Обычная функция:

class Button {
  constructor() {
    this.count = 0;
  }
  
  // Нужно явно привязать this
  handleClick = function() {
    this.count++;
    console.log(this.count);
  }.bind(this); // ВАЖНО: bind
}

const btn = new Button();
document.addEventListener('click', btn.handleClick); // Нужен bind

Стрелочная функция:

class Button {
  constructor() {
    this.count = 0;
  }
  
  // Стрелочная - this автоматически привязана
  handleClick = () => {
    this.count++;
    console.log(this.count);
  }; // Не нужен bind
}

const btn = new Button();
document.addEventListener('click', btn.handleClick); // Работает!

8. Метод super в классах

Обычная функция может использовать super:

// ✅ Обычная функция (constructor) может использовать super
class Animal {
  speak() {
    console.log('Sound');
  }
}

class Dog extends Animal {
  speak() {
    super.speak(); // Работает
    console.log('Woof!');
  }
}

const dog = new Dog();
dog.speak(); // 'Sound', 'Woof!'

// ❌ Стрелочная - super может не сработать как ожидается
class CatClass extends Animal {
  meow = () => {
    // super здесь может быть undefined
    super.speak(); // Может не сработать
  };
}

Таблица различий

ОсобенностьОбычная функцияСтрелочная
new конструктор✅ Да❌ Нет
Собственный this✅ Да❌ Наследует
prototype✅ Есть❌ Нет
arguments✅ Есть❌ Нет
Hoisting✅ Полный❌ Временная мертвая зона
bind/call/apply✅ Работают❌ Не меняют this
super✅ Работает⚠️ Может быть проблема

Когда использовать что

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

  • Конструкторов (классов)
  • Методов, где нужен свой this
  • Функций, которые вызываются с new

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

  • Callback-ов (setTimeout, map, filter)
  • Методов в классах, где нужен this родителя
  • Коротких функций
  • Обработчиков событий в React
// ✅ ХОРОШО - обычная для конструктора
function User(name) {
  this.name = name;
}

// ✅ ХОРОШО - стрелочная для callback
users.map(user => ({ ...user, age: user.age + 1 }))

// ✅ ХОРОШО - стрелочная для обработчика в React
<button onClick={() => handleClick()}>Click</button>

// ❌ ПЛОХО - стрелочная как метод объекта
const obj = {
  name: 'Test',
  getName: () => this.name // this неправильный
};