Вопрос о методах среза и сплайсинга JavaScript
Я наткнулся на следующий код:
var f = function () {
var args = Array.prototype.slice.call(arguments).splice(1);
// some more code
};
В основном результат args
- это массив, который является копией arguments
без его первого элемента.
Но я не могу точно понять, почему f
arguments
(который является объектом, который содержит введенные функции в объект типа array) передается методу slice
и как slice(1)
удаляет первый элемент (позиционируется с индексом 0).
Может кто-нибудь объяснить это мне?
P.S. Код из этой частичной функции приложения
Ответы
Ответ 1
< Примечание >
Фактический код из этого связанного ответа:
var args = Array.prototype.slice.call(arguments, 1);
то есть. "срез", а не "сращивание"
</Примечание >
Прежде всего, метод slice
часто используется для сделать копию массива, который он вызывал:
var a = ['a', 'b', 'c'];
var b = a.slice(); // b is now a copy of a
var c = a.slice(1); // c is now ['b', 'c']
Итак, короткий ответ заключается в том, что код в основном имитирует:
arguments.slice(1); // discard 1st argument, gimme the rest
Однако вы не можете сделать это напрямую. специальный объект arguments
(доступен внутри контекста выполнения всех функций JavaScript), хотя Array-like в нем поддерживает индексирование с помощью []
с цифровыми клавишами, на самом деле не является массивом; Вы не можете на него .push
, .pop
выключить его или .slice
и т.д.
Способ выполнения этого кода заключается в "обмане" функции slice
(которая снова недоступна для объекта arguments
) для запуска в контексте arguments
, через Function.prototype.call
:
Array.prototype.slice // get a reference to the slice method
// available on all Arrays, then...
.call( // call it, ...
arguments, // making "this" point to arguments inside slice, and...
1 // pass 1 to slice as the first argument
)
Array.prototype.slice.call(arguments).splice(1)
выполняет одно и то же, но делает посторонний вызов splice(1)
, который удаляет элементы из массива, возвращаемого из Array.prototype.slice.call(arguments)
, начиная с индекса 1
и продолжая до конца массива. splice(1)
не работает в IE (технически отсутствует второй параметр, указывающий, сколько элементов требуется для удаления этого IE и ECMAScript).
Ответ 2
var args = Array.prototype.slice.call(arguments).splice(1);
Сначала берет копию arguments
(*), а затем удаляет из него все, кроме первого элемента (нестандартным образом), и назначает удаляемые элементы args
.
Дополнительный массив, создаваемый, затем измененный и выброшенный, является довольно избыточным. Лучше сказать - поскольку версия в ответе, с которой вы связаны, действительно:
var args = Array.prototype.slice.call(arguments, 1);
Приложение с частичной функцией также является признаком метода function.bind
, стандартизированным ECMAScript Fifth Edition. До тех пор, пока браузеры не внедрили его, вы можете подобрать резервную JS-родную версию внизу этого ответа.
*: array.slice()
- нормальная идиома для копирования массива, а array.slice(1)
- для принятия хвоста. Он должен быть явно указан через Array.prototype
, потому что arguments
не является массивом, хотя он выглядит точно так же, как и один, поэтому не имеет обычных методов массива. Это еще одна ошибка JavaScript.
Вы нередко видите людей, использующих методы Array.prototype
для объектов, которые не являются массивами; стандарт ECMAScript Third Edition не подходит для того, чтобы сказать, что это нормально для массива arguments
, но не, что вы также можете сделать это на других типах массивов, которые могут быть хозяевами объекты, такие как NodeList или HTMLCollection. Хотя вы можете избежать вызова методов Array.prototype
для не-Array во многих браузерах сегодня, единственное, на что это действительно безопасно, - это arguments
.
Ответ 3
Возвращаемое значение сплайсинга - это массив элементов, которые были удалены,
но исходный массив (или подобный массиву объект) усекается в индексе сплайсинга.
Создание копии со срезом сохраняет исходный массив аргументов,
предположительно для использования позже в функции.
В этом случае тот же результат может быть получен с args = [].slice.call(arguments, 1)
function handleArguments(){
var A= [].slice.call(arguments).splice(1);
//arguments is unchanged
var s= 'A='+A+'\narguments.length='+arguments.length;
var B= [].splice.call(arguments, 1);
// arguments now contains only the first parameter
s+= '\n\nB='+B+'\narguments.length='+arguments.length;
return s;
}
// test
alert(handleArguments(1, 2, 3, 4));
returned value:
//var A= [].slice.call(arguments).splice(1);
A=2,3,4
arguments.length=4
//var B= [].splice.call(arguments, 1);
B=2,3,4
arguments.length=1