Подтвердить что ты не робот

Вопрос о методах среза и сплайсинга 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. Код из этой частичной функции приложения

4b9b3361

Ответ 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