What is arguments pseudo-Array in JavaScript
arguments is a function-local object in regular (non-arrow) JavaScript functions that automatically collects all passed arguments into an indexed, array-like structure.
Theory
TL;DR
- Like a cashier's bag that collects everything handed over, even extras you never named
- Array-like (has indices +
length) but is anObject, not anArray- no.map()or.forEach() - In strict mode, the live link between
arguments[i]and named params is disabled - Arrow functions don't have their own
arguments; they inherit from the outer scope - Decision: use rest params (
...args) in all new code;argumentsonly for legacy or IE11 contexts
Quick example
function greet(name, age) {
console.log(arguments[0]); // "Alice" - access by index
console.log(arguments.length); // 3 - counts all, even extras
console.log(Array.isArray(arguments)); // false - not a real Array
}
greet("Alice", 30, "NYC");Three arguments were passed but only two were declared. arguments.length shows 3 - it captures everything, not just the named ones.
Key difference
arguments works like an array for basic access (arguments[0], arguments.length) but is an Object without Array prototype methods. Calling arguments.forEach(...) throws a TypeError. To use array operations, convert first: Array.from(arguments) or [...arguments]. The design saves memory for simple indexed lookups but adds an extra step when you need filtering or mapping.
When to use
- Legacy browser support (IE11 or untranspiled environments):
argumentsworks without polyfills - Quick debug logging:
console.log(arguments)shows all inputs in one call - Dynamic argument count in older utility code that predates rest params
- New code: always reach for
...args; it gives a real Array with no conversion needed
How the engine handles this
In V8 (Chrome and Node.js), when a regular function executes, the engine creates an Arguments exotic object on the call stack. In non-strict mode, it maps arguments[i] directly to the corresponding named parameter through a hidden parameter map with getters and setters. Change a inside the function and arguments[0] updates too. Strict mode disables this link entirely - named params and arguments[i] become independent copies. Arrow functions skip arguments creation and inherit from the enclosing scope.
Common mistakes
Calling array methods directly:
function sum() {
let total = 0;
arguments.forEach(x => total += x); // TypeError: arguments.forEach is not a function
}Fix: Array.from(arguments).forEach(...) or switch to rest params.
Expecting arrow functions to have arguments:
const fn = () => console.log(arguments); // ReferenceError or outer scope's argumentsFix: const fn = (...args) => console.log(args);
Unexpected parameter aliasing in non-strict mode:
function add(a, b) {
arguments[0] = 100;
return a + b; // Returns 140, not 42 - a changed with arguments[0]
}
add(2, 40);Changing arguments[i] also changes the named param. Adding 'use strict' breaks that link.
Strict mode confusion:
'use strict';
function fn(a) {
a = 2;
console.log(arguments[0]); // Still 1 - no live mapping in strict mode
}
fn(1);Real-world usage
- Express.js (pre-ES6): route handlers inspected
argumentsfor dynamic middleware chains - jQuery: legacy event handlers read
argumentsfor extra event data in plugins - Lodash: utility functions converted
argumentsinternally for variadic input - Pre-ES6 conversion pattern:
Array.prototype.slice.call(arguments)beforeArray.fromexisted
| Feature | arguments | Rest params (...args) |
|---|---|---|
| Type | Object | Array |
| Array methods | No (convert first) | Yes |
| Strict mode mapping | Disabled | N/A |
| Arrow functions | Inherited, not own | Yes |
| New code | No | Yes |
Follow-up questions
Q: Why isn't arguments a real Array?
A: Memory optimization. The engine skips allocating a full Array object for simple indexed access. You only convert when you need array methods.
Q: What changes in strict mode?
A: The live parameter map is disabled. Changing a named param no longer updates arguments[i], and vice versa. They are independent after the function starts.
Q: Can you use arguments in arrow functions?
A: No own arguments is created. If you reference it inside an arrow, you get the outer regular function's arguments, or a ReferenceError if there's no enclosing regular function.
Q: How to convert arguments to an array in pre-ES6 code?
A: Array.prototype.slice.call(arguments) was the standard before Array.from and spread syntax.
Q: In V8, when is the parameter map for arguments created?
A: On function entry, for non-strict regular functions. It has getters and setters linking arguments properties to parameter slots. Strict mode and arrow functions skip it to prevent aliasing bugs.
Examples
Basic: summing any number of values
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)); // 30No parameters declared, but the function handles any count. arguments.length drives the loop. This is the classic pattern you'll find in pre-ES6 utility libraries.
Intermediate: legacy middleware logger
// Pre-ES6 Express-style logger - still found in older codebases
function logRequest() {
var args = Array.from(arguments);
console.log('Received ' + args.length + ' args:', args);
// args[0] = path, args[1] = handler, rest = middleware fns
}
logRequest('/users', handler, authMiddleware, rateLimiter);
// Received 4 args: ['/users', fn, fn, fn]Array.from converts arguments to a real array before any array operations. I've seen this exact pattern in Express codebases from 2014-2016 that were never updated - it still runs, but rest params make the intent clearer.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.