Що таке псевдомасив arguments у JavaScript
arguments - це вбудований об'єкт, який автоматично з'являється у звичайних (не стрілкових) функціях JavaScript і збирає всі передані аргументи в індексовану структуру, схожу на масив.
Теорія
TL;DR
- Як пакет у касира: туди потрапляє все, що ти передаєш, навіть якщо не назвав це в сигнатурі
- Має індекси і
length, але єObject, а неArray- методів.map()або.forEach()немає - У строгому режимі (
'use strict') живий зв'язок міжarguments[i]і іменованими параметрами вимикається - Стрілкові функції не створюють власного
arguments; вони беруть його з зовнішньої функції - Рішення: у новому коді завжди
...args;argumentsтільки для legacy-коду або IE11
Швидкий приклад
function greet(name, age) {
console.log(arguments[0]); // "Alice" - доступ за індексом
console.log(arguments.length); // 3 - рахує все, навіть зайве
console.log(Array.isArray(arguments)); // false - не справжній Array
}
greet("Alice", 30, "NYC");Передано три аргументи, оголошено тільки два. arguments.length показує 3 - захоплюється все, не тільки іменовані параметри.
Головна різниця
arguments поводиться як масив для базового доступу (arguments[0], arguments.length), але є Object без методів Array-прототипу. Виклик arguments.forEach(...) кидає TypeError. Щоб використовувати операції над масивами, потрібна конвертація: Array.from(arguments) або [...arguments]. Така конструкція економить пам'ять для простого індексного доступу, але вимагає додаткового кроку для фільтрації чи маппінгу.
Коли використовувати
- Підтримка старих браузерів (IE11 або середовища без транспіляції):
argumentsне потребує поліфілів - Швидке дебаг-логування:
console.log(arguments)показує всі вхідні дані одним рядком - Динамічна кількість аргументів у старому утилітному коді, що з'явився до rest-параметрів
- Новий код: завжди
...args; повертає справжній Array без додаткової конвертації
Як рушій з цим працює
У V8 (Chrome і Node.js) під час виклику звичайної функції рушій створює Arguments exotic object на стеку викликів. У нестрогому режимі між arguments[i] і відповідним іменованим параметром встановлюється прихована карта параметрів (parameter map) із геттерами і сеттерами. Зміна a всередині функції автоматично оновлює arguments[0]. Строгий режим повністю відключає цей зв'язок - іменовані параметри та arguments[i] стають незалежними. Стрілкові функції arguments не створюють і беруть його з охоплюючої функції.
Типові помилки
Виклик методів масиву напряму:
function sum() {
let total = 0;
arguments.forEach(x => total += x); // TypeError: arguments.forEach is not a function
}Виправлення: Array.from(arguments).forEach(...) або перехід на rest-параметри.
Припускати, що стрілкові функції мають arguments:
const fn = () => console.log(arguments); // ReferenceError або arguments зовнішньої функціїВиправлення: const fn = (...args) => console.log(args);
Несподіване аліасування параметрів у нестрогому режимі:
function add(a, b) {
arguments[0] = 100;
return a + b; // Повертає 140, а не 42 - a змінилося разом з arguments[0]
}
add(2, 40);Зміна arguments[i] змінює і відповідний іменований параметр. 'use strict' розриває цей зв'язок.
Плутанина зі строгим режимом:
'use strict';
function fn(a) {
a = 2;
console.log(arguments[0]); // Залишається 1 - у строгому режимі зв'язку немає
}
fn(1);Де зустрічається
- Express.js до ES6: обробники маршрутів перевіряли
argumentsдля динамічних ланцюжків middleware - jQuery: legacy-обробники подій зчитували
argumentsдля додаткових даних у плагінах - Lodash: утилітні функції конвертували
argumentsвсередині для variadic-викликів - Патерн конвертації до ES6:
Array.prototype.slice.call(arguments)замістьArray.from
| Властивість | arguments | Rest-параметри (...args) |
|---|---|---|
| Тип | Object | Array |
| Методи масиву | Ні (потрібна конвертація) | Так |
| Зв'язок у strict mode | Вимкнено | Не застосовно |
| Стрілкові функції | Успадкований, не власний | Так |
| Новий код | Ні | Так |
Питання на співбесіді
Q: Чому arguments не є справжнім Array?
A: Оптимізація пам'яті. Рушій уникає виділення повноцінного Array-об'єкта для простого індексного доступу. Конвертація потрібна тільки для методів масиву.
Q: Що змінюється у строгому режимі?
A: Жива карта параметрів вимикається. Зміна іменованого параметра більше не оновлює arguments[i], і навпаки. Після входу у функцію вони стають незалежними.
Q: Чи можна використовувати arguments у стрілкових функціях?
A: Власного arguments у стрілок немає. Якщо звернутися до нього всередині стрілки, отримаєш arguments зовнішньої звичайної функції або ReferenceError, якщо такої немає.
Q: Як конвертувати arguments у масив у коді до ES6?
A: Array.prototype.slice.call(arguments) - стандартний підхід до появи Array.from і spread-синтаксису.
Q: Як V8 створює карту параметрів для arguments?
A: Під час входу у функцію, для нестрогих звичайних функцій. Карта містить геттери і сеттери, що зв'язують властивості arguments зі слотами параметрів. Строгий режим і стрілкові функції пропускають цей крок, щоб уникнути помилок аліасування.
Приклади
Базовий: сума довільної кількості чисел
function sum() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(10, 20)); // 30Параметри не оголошені, але функція обробляє будь-яку їхню кількість. arguments.length керує циклом. Це класичний приклад, який зустрічається в pre-ES6 утилітних бібліотеках.
Проміжний: логер у стилі middleware (legacy-патерн)
// Логер у стилі Express до ES6 - такий код ще зустрічається у старих кодових базах
function logRequest() {
var args = Array.from(arguments);
console.log('Отримано ' + args.length + ' аргументів:', args);
// args[0] = шлях, args[1] = обробник, решта = middleware-функції
}
logRequest('/users', handler, authMiddleware, rateLimiter);
// Отримано 4 аргументів: ['/users', fn, fn, fn]Array.from конвертує arguments у справжній масив перед будь-якими операціями. Такий патерн часто зустрічається в Express-кодових базах 2014-2016 років, які так і не оновили - він досі працює, але rest-параметри зробили б намір значно зрозумілішим.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.