Почему у объекта arguments в JavaScript нет метода shift
Что проверяют
Понимаете ли вы разницу между массивом и массивоподобным объектом и откуда вообще берутся методы: из прототипа, а не из похожести на массив. Вопрос простой, но по нему видно, знаете ли вы прототипную модель и современные замены arguments.
Как отвечать
Прямой ответ: arguments не массив. Это обычный объект с числовыми ключами и свойством length, его прототип это Object.prototype, а не Array.prototype, поэтому ни shift, ни map, ни filter у него взяться неоткуда.
function f(a, b) {
Object.getPrototypeOf(arguments) === Object.prototype; // true
Array.isArray(arguments); // false
typeof arguments.shift; // "undefined"
}Стоит добавить, что методы массива обобщённые: им нужны только length и числовые ключи, поэтому Array.prototype.shift.call(arguments) отработает.
Но в современном коде так не пишут. Настоящий массив получают через Array.from(arguments) или спредом (он работает, потому что у arguments есть итератор), а лучше сразу объявляют rest-параметр:
function f(...args) {
const first = args.shift();
}Это полноценный массив, и заодно сигнатура честно говорит, что функция принимает произвольное число аргументов.
Где спотыкаются
Говорят, что arguments это урезанный массив. Урезанности нет, родства с массивом нет вообще. Практическое следствие: arguments.map не существует, а Array.prototype.map.call(arguments, fn) работает, и понимание, почему так, как раз и проверяют.
Забывают про стрелочные функции: своего arguments у них нет, внутри стрелки виден arguments ближайшей обычной функции, а вне функции это просто ошибка. Ровно та же история, что с this: у стрелки нет ни того, ни другого.
Не знают про связь с параметрами. В нестрогом режиме и при простом списке параметров элементы arguments связаны с именованными аргументами, и присваивание по индексу меняет параметр. Как только появляются значения по умолчанию, rest или деструктуризация, связь пропадает, и одинаковый на вид код ведёт себя по-разному. Это и есть причина, по которой arguments считают устаревшим.