Не могу связать воедино разрозненные (возможно поверхностные знания), помогите пожалуйста!
function func() {
var args = Array.prototype.slice.call(arguments); // ((1))
args.forEach(function(el, i, arr) {
return arr[i] = el.toUpperCase()
})
document.write(args) // [A,B,C]
};
func("a", "b", "c");
Собственно интересует эта самая строчка ((1)). Не могу связать то, что знаю, и понять как это действительно устроенно!
Ситуация данной функции мне абсолютно понятна, т.к. сам по себе arguments не является как таковым массивом, его можно сделать таковым, для этого и выполняется операция присваивания ((1))
Я понимаю, что:
Array.prototype - прототип массивов высшего уровня
slice() метод для копирования элементов массива, принимает 2 аргумента (1 начальный индекс копирования 2 конечный)
call метод явного указания контекста вызова, Т.Е., если я правильно понял, мы указываем, что this при вызове Array.prototype будет указывать именно на "псевдомассив" arguments.
Единственное, что я понимаю, это то, что args станет новым хранилищем для аргументов в данной функции, и к нему можно будет применять все стандартные методы Array.prototype, а как на самом деле выполняется это присваивание, зачем там slice, и какая функция у callв этом коде, мне не понятно!
Подобный вопрос я искал на stackoverflow, но не нашёл! Просьба к тем, у кого есть время, объяснить подробно на доступном языке!
Сначала я приведу порядок выполнения всего выражения пошагово, а затем каждый шаг постараюсь объяснить (насчет доступности не обещаю). Итак:
var args = Array.prototype.slice.call(arguments);
Упрощенный порядок выполнения:
Получение объекта метода Array.prototype.slice
Вызов метода slice.call, с передачей ему объекта arguments в качестве аргумента
Присвоение результата выполнения slice переменной args.
Пояснения:
Метод - это функция, а функции в JS являются объектами (экземплярами объектного типа Function).
Это означает что у всех функций есть общие методы из их прототипа (и call - один из таких методов, он является Function.prototype.call)
Метод call разово выполняет "свой" экземпляр функции (от имени которой вызван) в контексте объекта, переданного аргументом.
В данном случае, slice вызывается им в контексте объекта arguments - так, будто этот объект является массивом. Можно сказать что call временно "привязал" slice к объекту arguments, только на один вызов.
Результатом выполнения slice() является новый массив (новый экземпляр объектного типа Array), содержащий срез элементов того массива, от имени которого был вызван данный метод. При вызове этого метода без аргументов, срез содержит все элементы.
Возвращаемым из slice значением, является ссылка на этот новый массив - так как объекты всегда передаются по ссылке (и через аргументы, и в роли операндов, и при присваивании).
Таким образом, общий результат выполнения этого выражения: в переменнной args окажется ссылка на новый массив всех элементов объекта arguments.
Зачем это все, почему просто не вызвать arguments.slice()? Потому что arguments не является массивом - и у него просто нет методов из прототипа Array.
Фактически, это выражение с call делает то самое, что новичками ожидается от выражения arguments.slice().
p.s.:
С выходом ES6, у нас появился спред-оператор, которым можно упростить всю строку до
var args = [...arguments];
, и статический метод Array.from, который тоже весьма приятно выглядит:
var args = Array.from(arguments);
Сам 'массив' arguments на самом деле является псевдомассивом и как таковых функций перебора как для обычного массива у него нет. Array.prototype позволяет дать ему эти функции, создавая новый массив args как представителя класса Array. Дальше мы вызываем slice который просто копирует эллементы, а метод call просто перебирает данный псевдомассив. Эта строка просто нужна для того чтобы создать с псевдомассива - массив.
Продвижение своими сайтами как стратегия роста и независимости