Вопрос о методах slice и splice в JavaScript
-
21-09-2019 - |
Вопрос
Я наткнулся на следующий код:
var f = function () {
var args = Array.prototype.slice.call(arguments).splice(1);
// some more code
};
В принципе, результат в args
является массивом , который является копией arguments
без своего первого элемента.
Но чего я точно не могу понять, так это почему f
's arguments
(который является объектом, который содержит введенные аргументы функции в объект, подобный массиву) объект передается в slice
метод и каким образом slice(1)
удаляет первый элемент (расположенный с индексом 0).
Кто-нибудь, пожалуйста, может объяснить это для меня?
P.S.Код взят из этого частичная прикладная функция
Решение
<Note>
Фактический код из этого связанный ответ является:
var args = Array.prototype.slice.call(arguments, 1);
т. е."нарезать", а не "сращивать"
</Note>
Прежде всего, в 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-Нравится в том смысле, что он поддерживает индексацию через []
оператор с цифровыми клавишами на самом деле не является массивом;Ты не можешь .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 (технически отсутствует 2-й параметр, указывающий, сколько элементов для удаления требуется IE и ECMAScript).
Другие советы
var args = Array.prototype.slice.call(arguments).splice(1);
Сначала берется копия arguments
(*), затем удаляет из него все элементы, кроме первого (нестандартным способом), и присваивает удаляемые элементы args
.
Дополнительный массив, который создается, затем изменяется и выбрасывается, является совершенно избыточным.Было бы лучше сказать — поскольку версия в ответе, на который вы ссылались, действительно делает:
var args = Array.prototype.slice.call(arguments, 1);
Частичное функциональное применение также является особенностью function.bind
метод, стандартизированный пятым изданием ECMAScript.Пока браузеры не внедрили это, вы можете выбрать резервную версию JS-native в нижней части этот ответ.
*: array.slice()
является обычной идиомой для копирования массива, и array.slice(1)
за то, что взял за хвост.Он должен быть вызван явно через Array.prototype
потому что arguments
не является массивом, даже если он выглядит точно так же, как один, поэтому не имеет обычных методов массива.Это еще одна из странных ошибок JavaScript.
Вы довольно часто видите людей, использующих Array.prototype
методы для объектов, которые не являются массивами;стандарт третьей редакции ECMAScript делает все возможное, чтобы сказать, что это нормально делать для arguments
похожий на массив, но не что вы также можете сделать это с другими подобными массивам объектами, которые могут быть объектами хоста, такими как NodeList или HTMLCollection.Хотя тебе может сойти с рук звонок Array.prototype
методы в не-массиве во многих современных браузерах единственное место, где это действительно безопасно делать, - это arguments
.
Возвращаемое значение соединения представляет собой массив элементов, которые были удалены, но исходный массив (или массивоподобный объект) усекается по индексу соединения.
Создание копии с помощью slice сохраняет исходный массив arguments, предположительно для последующего использования в функции.
В этом случае тот же результат может быть получен с 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