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

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

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

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

То, что я не понимаю, - это call. Как это преобразовать document.querySelectorAll('a') из списка узлов в обычный массив?


person Yansky    schedule 24.01.2010    source источник
comment
Array.prototype.slice.call(document.querySelectorAll('a')); - это правильный способ написать кусок кода, который вы написали.   -  person vdegenne    schedule 03.04.2015
comment
Кстати, современный (и интуитивно понятный) метод ES6 для того же: Array.from. Так, например, это будет делать то же самое: Array.from (document.querySelectorAll ('a'));   -  person rugk    schedule 27.04.2019
comment
Отвечает ли это на ваш вопрос? как работает Array.prototype.slice.call ()?   -  person Henke    schedule 14.03.2021


Ответы (7)


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

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

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

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

person Max Shawabkeh    schedule 24.01.2010
comment
Также обратите внимание, что, хотя это семантически эквивалентно выражению Array.prototype.slice.call(...), на самом деле он создает экземпляр объекта массива ([]) только для доступа к его методу среза прототипа. Это потраченное впустую создание. Сказать Array.prototype.slice.call(...) вместо этого будет чище, хотя вы добавляете несколько символов в свой JS, если считаете ... - person Ben Zotto; 24.01.2010
comment
Обратите внимание, что в IE 8 и ниже это работает только с объектами Array, поэтому вы не сможете клонировать NodeLists - person Livingston Samuel; 07.03.2011
comment
@quixoto [] более надежен, поскольку Array может быть перезаписан чем-то другим. Если вам нужно повторно использовать Array#slice, рекомендуется кэшировать его. - person Mathias Bynens; 22.03.2011
comment
Если кто-то еще ищет способ сделать это в IE8, ознакомьтесь с этим вопросом stackoverflow.com/questions/3199588/ - person Liam Newmarch; 02.08.2011
comment
Я действительно видел, как этот шаблон появляется в исходном коде backbone.js: var array = []; var push = array.push; var slice = array.slice; var splice = array.splice; Делает ли он это из-за проблемы безопасности, о которой упоминает @MathiasBynens? - person owensmartin; 18.07.2014

В JavaScript методы объекта могут быть привязаны к другому объекту во время выполнения. Короче говоря, javascript позволяет объекту «заимствовать» метод другого объекта:

object1 = {
    name: 'Frank',
    greet() {
        alert(`Hello ${this.name}`);
    }
};

object2 = {
    name: 'Andy'
};

// Note that object2 has no greet method,
// but we may "borrow" from object1:

object1.greet.call(object2); // Will show an alert with 'Hello Andy'

call и apply методы объектов функций (в JavaScript функции также являются объектами) позволяют вам это делать. Итак, в вашем коде вы можете сказать, что NodeList заимствует метод среза массива. .slice() в качестве результата возвращает другой массив, который становится «преобразованным» массивом, который вы затем можете использовать.

person slebetman    schedule 24.01.2010
comment
Взрыв на ???? абстрактное объяснение концепции функций объекта javascript. Теперь вы можете применить его для call функции Array.prototype или [].prototype самостоятельно. - person Sourabh; 24.02.2020

Он извлекает функцию slice из Array. Затем он вызывает эту функцию, но использует результат document.querySelectorAll как объект this вместо фактического массива.

person Brian Campbell    schedule 24.01.2010

Это метод преобразования объектов, подобных массиву, в реальные массивы.

Некоторые из этих объектов включают:

  • arguments в функциях
  • NodeList (помните, что их содержимое может измениться после получения! поэтому преобразование их в массив - это способ их заморозить)
  • Коллекции jQuery, также известные как объекты jQuery (некоторый документ: API, type, учиться)

Это служит многим целям, например, объекты передаются по ссылке, а массивы передаются по значению.

Также обратите внимание, что первый аргумент 0 можно опустить, подробное объяснение здесь .

И для полноты картины существует также jQuery.makeArray ().

person Gras Double    schedule 09.04.2015

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

Это код, который у нас есть,

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

Давайте сначала его разберем,

  []    // Array object
.slice // Accessing the function 'slice' present in the prototype of Array
.call // Accessing the function 'call' present in the prototype of function object(slice)
(document.querySelectorAll('a'),0) 
    // 'call' can have arguments like, (thisArg, arg1,arg2...n). 
   // So here we are passing the 'thisArg' as an array like object,
  // that is a 'nodeList'. It will be served as 'this' object inside of slice function.
 // And finally setting 'start' argument of slice as '0' and leaving the 'end' 
// argument as 'undefined'

Шаг: 1 Выполнение функции call

  • Внутри call, кроме thisArg, остальные аргументы будут добавлены к списку аргументов.
  • Теперь функция slice будет вызываться путем привязки ее значения this как thisArg (массив, подобный объекту, поступил из document.querySelector) и со списком аргументов. т.е.] аргумент start, содержащий 0

Шаг: 2 Выполнение slice функции, вызванной внутри call

  • start будет присвоено переменной s как 0
  • поскольку end равно undefined, this.length будет храниться в e
  • пустой массив будет сохранен в переменной a
  • После выполнения вышеуказанных настроек произойдет следующая итерация.

    while(s < e) {
      a.push(this[s]);
      s++;
    }
    
  • в результате будет возвращен заполненный массив a.

PS Для лучшего понимания нашего сценария некоторые шаги, необходимые для нашего контекста, были проигнорированы в исходном алгоритме call и нарезать.

person Rajaprabhu Aravindasamy    schedule 15.03.2016
comment
Очень красивое пошаговое объяснение. Потрясающий! Спасибо :) - person kittu; 15.04.2017
comment
Хорошее объяснение. - person Naveen DA; 14.07.2017

Из ES6: просто создайте массив с помощью Array.from (element.children) или Array.from ({length: 5})

person Мони    schedule 30.10.2017

Это тоже может помочь.

метод нарезки

Описание:

slice does not alter the original array. It returns a shallow copy of elements from the original array. Elements of the original array are copied into the returned array.

Метод slice () возвращает неглубокую копию части массива в новый объект массива, выбранный от начала до конца (конец не включен), где начало и конец представляют собой индекс элементов в этом массиве. Исходный массив не будет изменен. см. больше: Reference / Global_Objects / Array / slice

метод вызова

Описание:

Вызов () позволяет назначать функцию / метод, принадлежащую одному объекту, и вызывать их для другого объекта.

Метод call () вызывает функцию с данным значением this и аргументами, предоставленными индивидуально. call () предоставляет новое значение this функции / методу. С call () вы можете написать метод один раз, а затем унаследовать его от другого объекта, без необходимости переписывать метод для нового объекта.

см. больше: Reference / Global_Objects / Function / call

person Hamdy Saady    schedule 27.08.2020