Пошук уроків, статей та іншого контенту
Навчіться працювати з довільною кількістю аргументів за допомогою ...args та познайомтеся з історичним об'єктом arguments. Порівняйте обидва підходи та дізнайтеся, чому в сучасному JavaScript зазвичай використовують Rest Parameters.
Функція може приймати різну кількість аргументів. Наприклад, функція для додавання чисел має працювати не лише з двома значеннями:
sum(2, 3);
sum(2, 3, 4, 5);
sum(10);У JavaScript для роботи з усіма переданими аргументами існують два підходи:
сучасний синтаксис Rest Parameters — ...args;
історичний об'єкт arguments.
Rest Parameters позначаються трьома крапками перед останнім параметром функції:
function sum(...numbers) {
// numbers — звичайний масив
return numbers.reduce((total, number) => total + number, 0);
}
console.log(sum(2, 3)); // 5
console.log(sum(2, 3, 4, 5)); // 14
console.log(sum()); // 0Усі аргументи, для яких не вистачило іменованих параметрів, збираються в масив numbers.
Назва numbers довільна. Часто використовують:
args — загальна назва для аргументів;
numbers — якщо функція працює з числами;
items — якщо функція працює з елементами;
messages — якщо функція працює з повідомленнями.
Rest-параметр може бути розташований після звичайних параметрів:
function introduce(greeting, ...names) {
return `${greeting}, ${names.join(", ")}!`;
}
console.log(introduce("Привіт", "Олено", "Андрію"));
// Привіт, Олено, Андрію!У цьому прикладі:
greeting отримує перший аргумент;
names містить усі наступні аргументи.
Якщо додаткових аргументів немає, rest-параметр буде порожнім масивом:
function showUsers(firstUser, ...otherUsers) {
console.log(firstUser);
console.log(otherUsers);
}
showUsers("Anna");
// Anna
// []Правильно:
function process(first, second, ...rest) {
console.log(first, second, rest);
}Неправильно:
// SyntaxError
function process(...rest, last) {
console.log(rest, last);
}Rest-параметр збирає всі залишкові аргументи, тому після нього не може бути інших параметрів.
Оскільки args є звичайним масивом, до нього можна застосовувати всі методи масивів:
function getPositiveNumbers(...numbers) {
return numbers
.filter((number) => number > 0)
.map((number) => number * 2);
}
console.log(getPositiveNumbers(-3, 2, 5, -1));
// [4, 10]Також можна використовувати:
map;
filter;
reduce;
find;
includes;
slice;
join;
sort.
Розглянемо функцію, яка обчислює середнє значення будь-якої кількості чисел:
function average(...numbers) {
if (numbers.length === 0) {
return 0;
}
const total = numbers.reduce(
(sum, number) => sum + number,
0
);
return total / numbers.length;
}
console.log(average(10, 20, 30)); // 20
console.log(average(5, 10)); // 7.5
console.log(average()); // 0Rest Parameters зручно використовувати, коли кількість значень заздалегідь невідома або може змінюватися.
argumentsДо появи Rest Parameters функції використовували спеціальний об'єкт arguments. Він містить усі аргументи, передані функції:
function showArguments() {
console.log(arguments.length);
console.log(arguments[0]);
console.log(arguments[1]);
}
showArguments("JavaScript", "TypeScript");
// 2
// JavaScript
// TypeScriptarguments має:
властивість length;
числові індекси;
значення переданих аргументів.
Проте arguments не є звичайним масивом.
function checkArguments() {
console.log(Array.isArray(arguments));
}
checkArguments(1, 2, 3); // falseЧерез це методи масивів не можна безпосередньо викликати на arguments:
function doubleArguments() {
// TypeError: arguments.map is not a function
return arguments.map((number) => number * 2);
}Щоб скористатися методами масиву, arguments спочатку потрібно перетворити на масив.
arguments на масивЗа допомогою Array.from:
function doubleArguments() {
const numbers = Array.from(arguments);
return numbers.map((number) => number * 2);
}
console.log(doubleArguments(2, 4, 6));
// [4, 8, 12]За допомогою оператора розпилення:
function doubleArguments() {
const numbers = [...arguments];
return numbers.map((number) => number * 2);
}
console.log(doubleArguments(2, 4, 6));
// [4, 8, 12]За допомогою Array.prototype.slice:
function doubleArguments() {
const numbers = Array.prototype.slice.call(arguments);
return numbers.map((number) => number * 2);
}
console.log(doubleArguments(2, 4, 6));
// [4, 8, 12]Сьогодні найчастіше використовують Array.from або оператор розпилення, але ще краще одразу застосувати Rest Parameters.
argumentsfunction withRest(...args) {
console.log(args);
console.log(Array.isArray(args));
}
withRest("a", "b", "c");
// ["a", "b", "c"]
// trueargumentsfunction withArguments() {
console.log(arguments);
console.log(Array.isArray(arguments));
}
withArguments("a", "b", "c");
// Arguments(3) ["a", "b", "c"]
// falseОсновні відмінності:
Rest Parameters створюють справжній масив.
arguments є масивоподібним об'єктом, але не масивом.
Rest Parameters можна використовувати в стрілкових функціях.
arguments недоступний у стрілкових функціях як локальний об'єкт.
Rest Parameters краще описують призначення параметра в коді.
З Rest Parameters не потрібно вручну перетворювати значення на масив.
arguments і стрілкові функціїУ звичайної функції є власний об'єкт arguments:
function regularFunction() {
console.log(arguments.length);
}
regularFunction(1, 2, 3); // 3У стрілкової функції власного arguments немає:
const arrowFunction = () => {
// arguments не належить цій функції
};Якщо в зовнішній звичайній функції є arguments, стрілкова функція може звернутися до нього через лексичне оточення. Але це зазвичай робить код менш зрозумілим:
function outer() {
const inner = () => {
console.log(arguments.length);
};
inner();
}
outer("a", "b"); // 2Для стрілкових функцій потрібно використовувати Rest Parameters:
const showValues = (...values) => {
console.log(values);
};
showValues(1, 2, 3);
// [1, 2, 3]argumentsУ звичайній нестрогій функції значення arguments історично може бути пов'язане зі значенням іменованого параметра:
function updateValue(value) {
value = 10;
console.log(value);
console.log(arguments[0]);
}
updateValue(5);
// 10
// 10Зміна value змінює і arguments[0].
У строгому режимі цей зв'язок відсутній:
"use strict";
function updateValue(value) {
value = 10;
console.log(value);
console.log(arguments[0]);
}
updateValue(5);
// 10
// 5Така поведінка є ще однією причиною не покладатися на arguments у новому коді. Rest Parameters не мають цієї особливості:
function updateValue(...values) {
values[0] = 10;
console.log(values);
}
updateValue(5);
// [10]Якщо функція очікує фіксовану кількість аргументів, оголошуйте їх явно:
function createUser(name, age) {
return {
name,
age
};
}Якщо функція може отримувати додаткові аргументи, використовуйте rest-параметр:
function createMessage(type, ...parts) {
return {
type,
text: parts.join(" ")
};
}
console.log(createMessage("error", "Не вдалося", "зберегти", "дані"));
// { type: "error", text: "Не вдалося зберегти дані" }Явні параметри покращують читабельність, а rest-параметр зручно використовувати для невизначеної кількості наступних значень.
Rest Parameters збирають аргументи в масив, а оператор розпилення виконує зворотну операцію — розгортає масив у окремі аргументи:
function sum(...numbers) {
return numbers.reduce((total, number) => total + number, 0);
}
const values = [3, 7, 10];
console.log(sum(...values)); // 20У виклику sum(...values) масив [3, 7, 10] перетворюється на послідовність аргументів:
sum(3, 7, 10);Це корисно, коли функція приймає довільну кількість аргументів, а дані вже зберігаються в масиві.
// SyntaxError
function collect(...items, lastItem) {
return items;
}Rest-параметр повинен бути останнім.
arguments у стрілковій функціїconst sum = () => {
// arguments не є локальним об'єктом цієї функції
};Використовуйте:
const sum = (...numbers) => {
return numbers.reduce((total, number) => total + number, 0);
};arguments — це масивfunction process() {
// Помилка: у arguments немає методу map
// return arguments.map((item) => item);
}Перетворіть його на масив:
function process() {
return Array.from(arguments).map((item) => String(item));
}
console.log(process(1, 2, 3));
// ["1", "2", "3"]argumentsЯкщо функція пишеться в сучасному JavaScript і їй потрібна довільна кількість аргументів, зазвичай краще одразу використати Rest Parameters:
function logValues(...values) {
values.forEach((value) => {
console.log(value);
});
}Цей варіант коротший і зрозуміліший за роботу з arguments.
arguments все ще можна зустрітиarguments може траплятися:
у старому коді;
у застарілих бібліотеках;
у коді, який підтримує старі підходи до JavaScript;
під час супроводу вже наявного проєкту.
Знати arguments потрібно для читання такого коду, але для нового коду перевагу зазвичай надають Rest Parameters.
Rest Parameters записуються як ...args.
Вони збирають додаткові аргументи у звичайний масив.
Rest-параметр повинен бути останнім параметром функції.
Його можна використовувати у звичайних і стрілкових функціях.
arguments — історичний масивоподібний об'єкт.
arguments має індекси та length, але не має стандартних методів масиву.
Для роботи з arguments його потрібно перетворити на масив.
У сучасному JavaScript для довільної кількості аргументів зазвичай використовують Rest Parameters.
Оператор розпилення ... може виконувати зворотну операцію: передавати елементи масиву як окремі аргументи.