JavaScript · Синтаксис · Промежуточный
Стрелочные функции и this
Освой синтаксис стрелочных функций и пойми как `this` ведёт себя по-разному в стрелочных и обычных функциях — ключевое различие для классов, колбэков и обработчиков событий.
Краткое введение в тему и пояснения перед упражнениями (упражнения ниже):
Стрелочные функции в методах массива, классах и промисах
#Стрелочные vs обычные функции — справочник
#Упражнения:
Переписать как стрелочную функцию
#Перепиши функцию `greet` как стрелочную функцию, присвоенную в `const`. Поведение должно быть идентичным.
function greet(name) {
return "Hello, " + name + "!";
}
console.log(greet("Alice"));
Решение
const greet = name => "Hello, " + name + "!";
console.log(greet("Alice"));
Неявный возврат — сократить до одной строки
#Сократи `multiply` до однострочной стрелочной функции с неявным возвратом.
const multiply = (a, b) => {
return a * b;
};
console.log(multiply(3, 4));
Решение
const multiply = (a, b) => a * b;
console.log(multiply(3, 4));
this в методе объекта — почему стрелка ломает
#Метод `describe` использует стрелочную функцию и возвращает неправильный результат. Исправь его так чтобы `this` правильно ссылался на объект.
const user = {
name: "Alice",
age: 30,
describe: () => {
return `${this.name} is ${this.age} years old`;
}
};
console.log(user.describe());
Решение
const user = {
name: "Alice",
age: 30,
describe() {
return `${this.name} is ${this.age} years old`;
}
};
console.log(user.describe());
Исправить this в колбэке setTimeout
#Класс `DelayedGreeter` должен вывести приветствие через 0мс, но `this.name` является undefined. Исправь с помощью стрелочной функции.
class DelayedGreeter {
constructor(name) {
this.name = name;
}
greet() {
setTimeout(function() {
console.log("Hello, " + this.name + "!");
}, 0);
}
}
new DelayedGreeter("Alice").greet();
Решение
class DelayedGreeter {
constructor(name) {
this.name = name;
}
greet() {
setTimeout(() => {
console.log("Hello, " + this.name + "!");
}, 0);
}
}
new DelayedGreeter("Alice").greet();
Стрелочные функции в map и filter
#Из массива `products` отфильтруй только товары с `price > 100` и преобразуй каждый только в `name`. Используй стрелочные функции для обеих операций. Выведи результат.
const products = [
{ name: "Laptop", price: 999 },
{ name: "Mouse", price: 25 },
{ name: "Monitor", price: 399 },
{ name: "Keyboard", price: 75 },
];
// твой код здесь
Решение
const products = [
{ name: "Laptop", price: 999 },
{ name: "Mouse", price: 25 },
{ name: "Monitor", price: 399 },
{ name: "Keyboard", price: 75 },
];
const result = products
.filter(p => p.price > 100)
.map(p => p.name);
console.log(result);
Вернуть объект из стрелочной функции
#Напиши стрелочную функцию `makeProduct`, принимающую `name` и `price` и возвращающую объект `{ name, price }` с неявным возвратом. Проверь с `"Laptop"` и `999`.
// твой код здесь
console.log(makeProduct("Laptop", 999));
Решение
const makeProduct = (name, price) => ({ name, price });
console.log(makeProduct("Laptop", 999));
Метод класса vs стрелочное свойство
#Класс `Counter` имеет `increment` как обычный метод и `decrement` как стрелочную функцию-свойство. Вызови оба на экземпляре и выведи `count` после каждого. Понаблюдай какая форма корректно работает после деструктуризации.
class Counter {
count = 0;
increment() {
this.count++;
}
decrement = () => {
this.count--;
};
}
const c = new Counter();
c.increment();
console.log(c.count);
c.decrement();
console.log(c.count);
// Деструктурируй и вызови — какой ломается?
const { increment, decrement } = c;
increment();
console.log(c.count);
decrement();
console.log(c.count);
Решение
class Counter {
count = 0;
increment() {
this.count++;
}
decrement = () => {
this.count--;
};
}
const c = new Counter();
c.increment();
console.log(c.count);
c.decrement();
console.log(c.count);
const { increment, decrement } = c;
try { increment(); } catch(e) { console.log("increment failed:", e.message); }
console.log(c.count);
decrement();
console.log(c.count);
Каррирование через вложенные стрелочные функции
#Напиши каррированную функцию `add` со стрелочными функциями: `add(a)(b)` должна возвращать `a + b`. Проверь через `add(3)(4)` и `add(10)(20)`.
// твой код здесь console.log(add(3)(4)); console.log(add(10)(20));
Решение
const add = a => b => a + b;
console.log(add(3)(4));
console.log(add(10)(20));
Стрелочные функции в цепочке промисов
#Завершить цепочку промисов: resolve со значением `42`, затем удвоить в `.then`, затем вывести результат в следующем `.then`. Используй стрелочные функции для обоих колбэков.
const p = new Promise(resolve => {
resolve(42);
});
p
.then(/* удвоить значение */)
.then(/* вывести результат */);
Решение
const p = new Promise(resolve => {
resolve(42);
});
p
.then(val => val * 2)
.then(val => console.log(val));
Выбрать правильный тип функции
#Код ниже имеет два бага: один метод неправильно использует стрелочную функцию, а один колбэк неправильно использует обычную функцию. Исправь оба.
class Playlist {
constructor(name) {
this.name = name;
this.songs = [];
}
// Должен выводить "Playlist: Rock"
describe: () => {
console.log("Playlist: " + this.name);
}
// Должен выводить каждую песню с названием плейлиста
printSongs() {
this.songs.forEach(function(song) {
console.log(this.name + ": " + song);
});
}
}
const pl = new Playlist("Rock");
pl.songs = ["AC/DC", "Led Zeppelin"];
pl.describe();
pl.printSongs();
Решение
class Playlist {
constructor(name) {
this.name = name;
this.songs = [];
}
describe() {
console.log("Playlist: " + this.name);
}
printSongs() {
this.songs.forEach(song => {
console.log(this.name + ": " + song);
});
}
}
const pl = new Playlist("Rock");
pl.songs = ["AC/DC", "Led Zeppelin"];
pl.describe();
pl.printSongs();