Что можно делать с обычной функцией и нельзя со стрелочной?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Что можно делать с обычной функцией и нельзя со стрелочной
Обычные функции (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 неправильный
};