Объяснение [] .slice.call в JavaScript?

197

Я наткнулся на этот удобный ярлык для преобразования DOM NodeList в обычный массив, но я должен признать, я не совсем понимаю, как это работает:

[].slice.call(document.querySelectorAll('a'), 0)

Итак, он начинается с пустого массива [], а затем sliceиспользуется для преобразования результата callв новый массив, да?

Немного не понимаю это call. Как это преобразовать document.querySelectorAll('a')из NodeList в обычный массив?

Янского
источник
5
Array.prototype.slice.call(document.querySelectorAll('a'));это правильный способ написать кусок кода, который вы написали.
августа
4
Кстати, современный (и интуитивно понятный) метод ES6 для того же Array.from. Так, например, это будет делать то же самое: Array.from (document.querySelectorAll ('a'));
rugk

Ответы:

158

Здесь происходит то, что вы вызываете, slice()как если бы это была функция NodeListиспользования call(). Что slice()же в этом случае создать пустой массив, то итерацию через объект он запущен (первоначально массив, теперь NodeList) и держать добавление элементов этого объекта для пустого массива он создал, который в конце концов вернулся. Вот статья об этом .

РЕДАКТИРОВАТЬ:

Итак, он начинается с пустого массива [], затем slice используется для преобразования результата вызова в новый массив, да?

Это не правильно. [].sliceвозвращает объект функции. Функциональный объект имеет функцию, call()которая вызывает функцию, назначающую первый параметр call()для this; другими словами, заставляя функцию думать, что она вызывается из параметра ( NodeListвозвращаемого document.querySelectorAll('a')), а не из массива.

Макс Шавабке
источник
59
Также обратите внимание, что хотя это семантически эквивалентно высказыванию Array.prototype.slice.call(...), оно на самом деле создает экземпляр объекта array ( []) только для доступа к своему методу среза прототипа. Это пустая инстанция. Array.prototype.slice.call(...)Вместо этого говорить чище, хотя вы добавляете несколько символов к своему JS, если вы считаете ...
Бен Зотто
Обратите внимание, что это работает в IE 8 и ниже только для объектов Array, поэтому вы не сможете клонировать NodeLists
Livingston Samuel
5
@quixoto []более надежен, поскольку Arrayможет быть перезаписан на что-то другое. Если вам нужно использовать повторно Array#slice, рекомендуется кэшировать его.
Матиас Биненс,
2
Если кто-то еще ищет способ сделать это в IE8, проверьте этот вопрос stackoverflow.com/questions/3199588/…
Лиам Ньюмарч
1
Я действительно видел этот шаблон в исходном коде backbone.js: var array = []; var push = array.push; var slice = array.slice; var splice = array.splice;делает ли он это из-за проблемы безопасности, о которой упоминает @MathiasBynens?
owensmartin