Как преобразовать объект arguments в массив в JavaScript
Что проверяют
Знаете ли вы, что arguments это массивоподобный объект, а не массив, и чем его заменили в ES2015. Уточняющий вопрос почти всегда один: зачем вообще arguments, если есть rest-параметры.
Как отвечать
Сначала объясните, что это за объект: у него есть индексы и length, но нет методов массива (map, filter, reduce), а Array.isArray(arguments) вернёт false. Начиная с ES2015 он ещё и итерируемый. Отсюда способы:
Array.from(arguments): работает с любым массивоподобным объектом, вторым аргументом можно сразу передать функцию преобразования;[...arguments]: спред работает, потому что уargumentsестьSymbol.iterator. На объекте вида{ length: 2, 0: 'a' }без итератора спред упадёт сTypeError, аArray.fromсправится;Array.prototype.slice.call(arguments): способ из эпохи ES5, встречается в старом коде и полифилах;- rest-параметры
function f(...args): правильный ответ для нового кода.argsсразу настоящий массив, сигнатура честно показывает переменное число аргументов, а TypeScript умеет его типизировать.
Добавьте пару фактов, которые отличают уверенный ответ:
- у стрелочных функций своего
argumentsнет, они берут его из внешней обычной функции; - в нестрогом режиме у функции с простыми параметрами
arguments[0]и первый параметр связаны: меняете одно, меняется другое. В строгом режиме и в модулях этой связи нет; - в строгом режиме обращение к
arguments.calleeбросаетTypeError.
Где спотыкаются
Называют arguments массивом и вызывают arguments.map(...) напрямую. Получают TypeError: arguments.map is not a function.
Пишут [...arguments] внутри стрелочной функции и удивляются результату: там это аргументы внешней функции, а на верхнем уровне ES-модуля arguments вообще не определён, будет ReferenceError.
Рассуждают о производительности по старым статьям, где slice.call(arguments) мешал оптимизации в V8. Для современного движка это не довод, довод в читаемости: в новом коде берут rest-параметры и к arguments не прикасаются.