Skip to main content

Що таке псевдомасив arguments у JavaScript

arguments - це вбудований об'єкт, який автоматично з'являється у звичайних (не стрілкових) функціях JavaScript і збирає всі передані аргументи в індексовану структуру, схожу на масив.

Теорія

TL;DR

  • Як пакет у касира: туди потрапляє все, що ти передаєш, навіть якщо не назвав це в сигнатурі
  • Має індекси і length, але є Object, а не Array - методів .map() або .forEach() немає
  • У строгому режимі ('use strict') живий зв'язок між arguments[i] і іменованими параметрами вимикається
  • Стрілкові функції не створюють власного arguments; вони беруть його з зовнішньої функції
  • Рішення: у новому коді завжди ...args; arguments тільки для legacy-коду або IE11

Швидкий приклад

javascript
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 не створюють і беруть його з охоплюючої функції.

Типові помилки

Виклик методів масиву напряму:

javascript
function sum() { let total = 0; arguments.forEach(x => total += x); // TypeError: arguments.forEach is not a function }

Виправлення: Array.from(arguments).forEach(...) або перехід на rest-параметри.

Припускати, що стрілкові функції мають arguments:

javascript
const fn = () => console.log(arguments); // ReferenceError або arguments зовнішньої функції

Виправлення: const fn = (...args) => console.log(args);

Несподіване аліасування параметрів у нестрогому режимі:

javascript
function add(a, b) { arguments[0] = 100; return a + b; // Повертає 140, а не 42 - a змінилося разом з arguments[0] } add(2, 40);

Зміна arguments[i] змінює і відповідний іменований параметр. 'use strict' розриває цей зв'язок.

Плутанина зі строгим режимом:

javascript
'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
ВластивістьargumentsRest-параметри (...args)
ТипObjectArray
Методи масивуНі (потрібна конвертація)Так
Зв'язок у 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 зі слотами параметрів. Строгий режим і стрілкові функції пропускають цей крок, щоб уникнути помилок аліасування.

Приклади

Базовий: сума довільної кількості чисел

javascript
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-патерн)

javascript
// Логер у стилі 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-параметри зробили б намір значно зрозумілішим.

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.

Дочитали статтю?