Добавить в корзинуПозвонить
Найти в Дзене
ovnoCod

Язык JavaScript - Повторяем стрелочные функции

Когда в 2015 году в JavaScript появились стрелочные функции, многие вздохнули с облегчением. Наконец-то можно писать короткие колбэки без function и return. Наконец-то this перестал быть проклятием. Наконец-то код стал красивее. Но, как у любой суперсилы, у стрелочных функций есть тёмная сторона. Они не везде подходят. Они ведут себя иначе. И если не понять эти различия, стрелка может выстрелить мимо цели. Сегодня мы повторим всё, что нужно знать о стрелочных функциях: от синтаксиса до подводных камней, от идеальных сценариев до тех мест, где они категорически не подходят. Посмотрите, как эволюционировала одна и та же функция: javascript // Способ 1: классическое объявление
function square(x) {
return x * x;
}
// Способ 2: Function Expression
const square = function(x) {
return x * x;
};
// Способ 3: стрелочная (многострочная)
const square = (x) => {
return x * x;
};
// Способ 4: стрелочная (максимально короткая)
const square = x => x * x; Что изменилось? javascript const getT
Оглавление
взято с ya.ru
взято с ya.ru

Стрелы времени: Почему стрелочные функции изменили JavaScript навсегда (и как не промахнуться)

Когда в 2015 году в JavaScript появились стрелочные функции, многие вздохнули с облегчением. Наконец-то можно писать короткие колбэки без function и return. Наконец-то this перестал быть проклятием. Наконец-то код стал красивее.

Но, как у любой суперсилы, у стрелочных функций есть тёмная сторона. Они не везде подходят. Они ведут себя иначе. И если не понять эти различия, стрелка может выстрелить мимо цели.

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

Часть 1. Рождение стрелки: от многословия к лаконичности

Посмотрите, как эволюционировала одна и та же функция:

javascript

// Способ 1: классическое объявление
function square(x) {
return x * x;
}

// Способ 2: Function Expression
const square = function(x) {
return x * x;
};

// Способ 3: стрелочная (многострочная)
const square = (x) => {
return x * x;
};

// Способ 4: стрелочная (максимально короткая)
const square = x => x * x;

Что изменилось?

  • Убрали слово function
  • Добавили стрелку =>
  • Если один параметр - скобки не нужны
  • Если тело - одно выражение - return и {} не нужны

Часть 2. Синтаксис от А до Я

2.1 Без параметров

javascript

const getTime = () => Date.now();
const hello = () => console.log("Привет!");

2.2 С одним параметром (скобки необязательны)

javascript

const double = x => x * 2;
const square = x => { return x * x; };
// со скобками нужен return

2.3 С несколькими параметрами (скобки обязательны)

javascript

const add = (a, b) => a + b;
const multiply = (a, b, c) => a * b * c;

2.4 С телом из нескольких выражений (нужны {} и return)

javascript

const process = (a, b) => {
const sum = a + b;
const product = a * b;
return { sum, product };
};

2.5 Возврат объекта (ловушка!)

javascript

// ❌ Не работает ({} воспринимается как блок кода)
const getUser = () => { name: "Анна", age: 25 };

// ✅ Правильно (оборачиваем в скобки)
const getUser = () => ({ name: "Анна", age: 25 });

// ✅ Или с явным return
const getUser = () => {
return { name: "Анна", age: 25 };
};

Часть 3. Главная магия: this не теряется

Это самое важное отличие стрелочных функций. У них нет своего this. Они берут this из внешнего контекста (лексическое связывание).

3.1 Проблема обычных функций

javascript

const user = {
name: "Анна",
greet: function() {
setTimeout(function() {
console.log(`Привет, ${this.name}`);
// undefined!
}, 1000);
}
};

user.greet();
// "Привет, undefined"

3.2 Решение со стрелкой

javascript

const user = {
name: "Анна",
greet: function() {
setTimeout(() => {
console.log(`Привет, ${this.name}`);
// "Привет, Анна"
}, 1000);
}
};

user.greet();
// "Привет, Анна"

Что произошло? Стрелка не создала свой this, а взяла его из внешней функции greet, где this = user.

3.3 Стрелка как метод объекта - НЕ ДЕЛАЙТЕ ТАК

javascript

const obj = {
name: "Объект",
arrowMethod: () => {
console.log(this.name);
// this = window (или undefined)
}
};

obj.arrowMethod();
// undefined

// Для методов объектов используйте обычные функции
const obj2 = {
name: "Объект",
regularMethod() {
console.log(this.name);
// "Объект"
}
};

Часть 4. Нет arguments

У стрелочных функций нет собственного псевдомассива arguments.

javascript

// Обычная функция - есть
function regular() {
console.log(arguments);
// [1, 2, 3]
}
regular(1, 2, 3);

// Стрелка - нет
const arrow = () => {
console.log(arguments);
// ReferenceError: arguments is not defined
};
arrow(1, 2, 3);

Что делать? Используйте rest-параметры:

javascript

const sum = (...numbers) => numbers.reduce((a, b) => a + b, 0);
console.log(sum(1, 2, 3, 4));
// 10

Часть 5. Нельзя использовать как конструктор

Стрелочные функции нельзя вызывать с new. У них нет свойства prototype.

javascript

const Person = (name) => {
this.name = name;
};

// const user = new Person("Анна"); // TypeError: Person is not a constructor

// Только обычные функции
function RegularPerson(name) {
this.name = name;
}
const user = new RegularPerson("Анна");
// ✅

Часть 6. Нет prototype

У стрелочных функций нет свойства prototype. Они легче и проще.

javascript

function regular() {}
const arrow = () => {};

console.log(regular.prototype);
// { constructor: regular }
console.log(arrow.prototype);
// undefined

Часть 7. Когда использовать стрелочные функции (✅)

7.1 Короткие колбэки для массивов

javascript

const doubled = numbers.map(n => n * 2);
const adults = users.filter(user => user.age >= 18);
const total = orders.reduce((sum, order) => sum + order.price, 0);

7.2 Цепочки операций

javascript

const result = data
.filter(item => item.isActive)
.map(item => item.value)
.reduce((sum, val) => sum + val, 0);

7.3 Промисы и асинхронный код

javascript

fetch('/api/user')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error));

7.4 setTimeout / setInterval

javascript

setTimeout(() => {
console.log("Прошла секунда");
}, 1000);

7.5 Внутри методов классов (для сохранения this)

javascript

class Button {
constructor(label) {
this.label = label;
}

handleClick = () => {
console.log(`Нажата кнопка ${this.label}`);
}
}

7.6 Функции высшего порядка

javascript

const multiplyBy = factor => x => x * factor;
const double = multiplyBy(2);
const triple = multiplyBy(3);

console.log(double(5));
// 10
console.log(triple(5));
// 15

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

8.1 Методы объектов (нужен свой this)

javascript

// Плохо
const counter = {
count: 0,
increment: () => {
this.count++;
// this — не counter!
}
};

// Хорошо
const counter = {
count: 0,
increment() {
this.count++;
}
};

8.2 Конструкторы

javascript

// Плохо
const Widget = (width, height) => {
this.width = width;
// не работает
};

// Хорошо
class Widget {
constructor(width, height) {
this.width = width;
this.height = height;
}
}

8.3 Функции, которым нужен свой arguments

javascript

// Плохо
const debug = (...args) => {
console.log(args);
// работает, но не arguments
};

// Хорошо (если нужен именно arguments)
function debug() {
console.log(arguments);
}

8.4 Генераторы

javascript

// Стрелки не могут быть генераторами
function* generator() {
yield 1;
yield 2;
}

8.5 Методы, которые используют super

javascript

class Parent {
method() {
console.log("Parent");
}
}

class Child extends Parent {
// ❌ Стрелка не работает с super
arrowMethod = () => {
super.method();
// Ошибка!
}

// ✅ Обычный метод работает
regularMethod() {
super.method();
// "Parent"
}
}

Часть 9. Стрелки и деструктуризация - идеальная пара

javascript

const users = [
{ name: "Анна", age: 25 },
{ name: "Борис", age: 30 }
];

// Красиво и читаемо
const names = users.map(({ name }) => name);
const adults = users.filter(({ age }) => age >= 18);
const totalAge = users.reduce((sum, { age }) => sum + age, 0);

Часть 10. Сравнение: стрелка vs обычная функция

-2

Часть 11. Реальные паттерны

11.1 Композиция функций

javascript

const compose = (f, g) => x => f(g(x));
const add1 = x => x + 1;
const multiply2 = x => x * 2;

const add1ThenMultiply2 = compose(multiply2, add1);
console.log(add1ThenMultiply2(5));
// (5 + 1) * 2 = 12

11.2 Каррирование

javascript

const multiply = a => b => a * b;
const double = multiply(2);
const triple = multiply(3);

console.log(double(5));
// 10
console.log(triple(5));
// 15

11.3 Условный рендеринг в React

jsx

const UserGreeting = ({ user, isLoggedIn }) => (
<div>
{isLoggedIn ? (
<h1>С возвращением, {user.name}!</h1>
) : (
<button onClick={() => login()}>Войти</button>
)}
</div>
);

11.4 Обработка событий с сохранением контекста

jsx

class SearchForm extends React.Component {
state = { query: "" };

handleChange = (e) => {
this.setState({ query: e.target.value });
// this = экземпляр
};

render() {
return <input onChange={this.handleChange} />;
}
}

Часть 12. Подводные камни

Камень #1: Возврат объекта без скобок

javascript

// ❌
const getUser = () => { name: "Анна" };
console.log(getUser());
// undefined

// ✅
const getUser = () => ({ name: "Анна" });

Камень #2: this в глобальной стрелке

javascript

// В браузере
const arrow = () => console.log(this);
arrow();
// window (не undefined!)

// В строгом режиме тоже window (обычная функция дала бы undefined)

Камень #3: Нечитаемая цепочка стрелок

javascript

// Плохо (слишком много стрелок подряд)
const result = data.map(x => x.items).filter(x => x.active).map(x => x.price).reduce((a, b) => a + b, 0);

// Хорошо (разбито на строки)
const result = data
.map(x => x.items)
.filter(x => x.active)
.map(x => x.price)
.reduce((sum, price) => sum + price, 0);

Камень #4: Слишком умная однострочка

javascript

// Плохо (непонятно)
const validate = user => user && user.age >= 18 && user.isActive || user.isAdmin;

// Хорошо (понятно)
const validate = user => {
if (!user) return false;
if (user.isAdmin) return true;
return user.age >= 18 && user.isActive;
};

Часть 13. Производительность (мифы и факты)

Миф: Стрелочные функции медленнее обычных.

Факт: Разница настолько мала, что вы её никогда не заметите. Современные движки оптимизируют стрелки отлично.

javascript

// Измерять бессмысленно - разница в наносекундах
console.time("regular");
for (let i = 0; i < 10000000; i++) {
(function(x) { return x * 2; })(i);
}
console.timeEnd("regular");

console.time("arrow");
for (let i = 0; i < 10000000; i++) {
(x => x * 2)(i);
}
console.timeEnd("arrow");

Выбирайте по читаемости, а не по скорости.

Итог: Манифест стрелочных функций

  1. Короткий синтаксис - пишите меньше, делайте больше.
  2. Нет своего this - берут из внешнего контекста (суперсила для колбэков).
  3. Не использовать как методы объектов - для методов нужны обычные функции.
  4. Не использовать как конструкторы - для классов есть class.
  5. Нет arguments - используйте ...rest.
  6. Идеальны для колбэков - map, filter, reduce, setTimeout, промисы.
  7. Читаемость важнее краткости - не жертвуйте понятностью ради одной строки.

Финальный тест (проверьте себя):

javascript

const obj = {
name: "JS",
getName: () => this.name
};
console.log(obj.getName());

const calculator = {
value: 10,
double: () => this.value * 2,
triple() { return this.value * 3; }
};
console.log(calculator.double());
console.log(calculator.triple());

const add = x => y => x + y;
const add5 = add(5);
console.log(add5(3));

Ответы: undefined (стрелка берёт глобальный this), NaN (this.value - undefined → NaN), 30, 8.

Стрелочные функции - это не просто синтаксический сахар. Это новый способ думать о функциях в JavaScript. Они делают код чище, избавляют от головной боли с this и открывают двери в мир функционального программирования. Но, как любой инструмент, они требуют понимания, когда их использовать, а когда лучше выбрать обычную функцию. Используйте их мудро, и ваш код станет красивее, понятнее и современнее. Стреляйте в цель!