Об'єкт arguments
arguments це вбудований об'єкт, доступний усередині будь-якої звичайної функції (але не стрілкової), який містить усі аргументи, передані в цю функцію при виклику. Він дозволяє працювати зі списком аргументів навіть тоді, коли параметри взагалі не оголошені.
Теорія
TL;DR
argumentsдоступний лише всередині звичайних функцій (function), не у стрілкових.- Це псевдомасив: є індекси і
length, але немаєmap,forEach,reduce. - Дає доступ до всіх переданих аргументів, навіть якщо параметри не оголошені.
- У нестрогому режимі
argumentsі параметри пов'язані: зміна одного змінює інше. - У стрілковій функції звернення до
argumentsбере його із зовнішньої функції, а якщо такої немає, будеReferenceError. - Сучасна і рекомендована заміна це rest параметри
...args.
Швидкий приклад
function showArguments() {
console.log(arguments);
}
showArguments("apple", 42, true);Результат у консолі:
[Arguments] { '0': 'apple', '1': 42, '2': true }Псевдомасив, а не масив
arguments виглядає як масив, але ним не є. У нього є:
- індекси (
0,1,2і далі), - властивість
length, - але немає методів масиву (
map,forEachі подібних).
Щоб отримати справжній масив, його треба сконвертувати:
const args = Array.from(arguments);
// або
const args2 = [...arguments];Приклад із доступом до аргументів без оголошених параметрів:
function sumAll() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}
console.log(sumAll(1, 2, 3, 4)); // 10Тут ми не оголошуємо параметрів, а просто беремо все, що передано, через arguments.
Відмінність від параметрів і їхній зв'язок
Поки значення не змінюють, параметри й arguments показують те саме:
function show(a, b) {
console.log(a, b);
console.log(arguments[0], arguments[1]);
}
show("x", "y");
// a, b -> "x", "y"
// arguments[0], arguments[1] -> "x", "y"Але у звичайних функціях у нестрогому режимі вони пов'язані: змінюється одне, змінюється й інше.
function demo(a) {
console.log(a, arguments[0]); // 10, 10
a = 20;
console.log(a, arguments[0]); // 20, 20
}
demo(10);Цей зв'язок не працює у строгому режимі ('use strict'), а також якщо у функції є параметри за замовчуванням, rest параметр або деструктуризація. Тому покладатися на нього не варто.
arguments у стрілкових функціях
const arrow = () => {
console.log(arguments); // ReferenceError
};
arrow(1, 2, 3);Чому так:
- Стрілкові функції не створюють власного об'єкта
arguments. - Якщо звернутися до нього, значення візьметься із зовнішньої звичайної функції, якщо вона є.
Наочно:
function outer() {
const inner = () => console.log(arguments[0]);
inner("ignored"); // "outer", бо це arguments зовнішньої функції
}
outer("outer");Це та сама логіка, що і з this: стрілкова функція не має ні власного this, ні arguments, ні super, ні new.target.
Rest параметри як сучасна заміна
Сучасний і безпечний спосіб замість arguments це rest параметри:
function sumAll(...args) {
return args.reduce((sum, n) => sum + n, 0);
}
console.log(sumAll(1, 2, 3)); // 6Переваги ...args над arguments:
- Це справжній масив (є
.map,.filter,.reduce). - Працює у стрілкових функціях.
- Немає плутанини з «пов'язаними» значеннями.
- Код виглядає чистіше й зрозуміліше.
Порівняння:
| Властивість | arguments | ...rest |
|---|---|---|
| Тип | Псевдомасив | Масив |
Методи масиву (map, forEach) | Немає | Є |
| Доступний у стрілкових функціях | Ні | Так |
| Пов'язаний з параметрами | Так, у нестрогому режимі | Ні |
| Сучасний спосіб | Застарілий | Рекомендований |
Приклад для запам'ятовування:
// Старий спосіб
function oldSum() {
return Array.from(arguments).reduce((a, b) => a + b);
}
// Новий спосіб
const newSum = (...nums) => nums.reduce((a, b) => a + b);
console.log(oldSum(1, 2, 3)); // 6
console.log(newSum(1, 2, 3)); // 6Типові помилки
- Викликати методи масиву прямо на
arguments.arguments.map(...)кинеTypeError: спочатку потрібенArray.from(arguments)або[...arguments]. - Очікувати
argumentsу стрілковій функції. Його там немає, буде значення зовнішньої функції абоReferenceError. - Покладатися на зв'язок з параметрами. У строгому режимі, а також за наявності значень за замовчуванням чи rest параметра, зв'язку немає.
- Думати, що
arguments.lengthдорівнюєfunc.length. Перше це кількість фактично переданих аргументів, друге це кількість оголошених параметрів до першого зі значенням за замовчуванням. - Передавати
argumentsдалі без копіювання. Це заважає оптимізаціям рушія і легко призводить до неочевидних багів; передавайте...args.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.