Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Що таке псевдомасив arguments у JavaScript». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**arguments** - це псевдомасив (array-like object) у звичайних функціях JavaScript, який збирає всі передані аргументи за індексом. ```javascript function sum() { return Array.from(arguments).reduce((a, b) => a + b, 0); } sum(1, 2, 3); // 6 ``` **Ключове:** має індекси і `length`, але без методів масиву. Стрілкові функції не мають власного `arguments`. Для нового коду використовуй `...args`.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**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` | Властивість | `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` зі слотами параметрів. Строгий режим і стрілкові функції пропускають цей крок, щоб уникнути помилок аліасування. ## Приклади ### Базовий: сума довільної кількості чисел ```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-параметри зробили б намір значно зрозумілішим.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.