Пояснення [] .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'));це правильний спосіб написання фрагмента коду, який ви написали.
vdegenne

4
До речі, сучасний (і інтуїтивно зрозумілий) метод ES6 для того ж є Array.from. Так, наприклад, це робиться так само: Array.from (document.querySelectorAll ('a'));
rugk

Відповіді:


158

Тут відбувається те, що ви дзвоните slice()так, ніби це було функцією NodeListвикористання call(). Що slice()в цьому випадку полягає в створенні порожнього масиву, потім повторіть його через об'єкт, на якому він працює (спочатку масив, тепер а NodeList), і продовжуйте додавати елементи цього об'єкта до створеного ним порожнього масиву, який з часом повертається. Ось стаття з цього приводу .

Редагувати:

Отже, він починається з порожнього масиву [], потім фрагмент використовується для перетворення результату виклику в новий масив, так?

Це не правильно. [].sliceповертає об’єкт функції. Об'єкт функції має функцію, call()яка викликає функцію, призначаючи перший параметр call()до this; іншими словами, змушуючи функцію думати, що вона викликається з параметра ( NodeListповертається document.querySelectorAll('a')), а не з масиву.


59
Тут також зауважте, що, хоча це семантично еквівалентно висловлюванню Array.prototype.slice.call(...), він фактично створює об'єкт масиву ( []) лише для доступу до методу фрагмента прототипу. Це даремна інстанція. Скажіть, Array.prototype.slice.call(...)натомість чистіше, хоча ви додасте кілька символів до свого JS, якщо рахуєте ...
Бен Зотто,

Зауважте, що це працює в IE 8 і нижче лише на об'єктах Array, тому ви не зможете клонувати NodeLists
Livingston Samuel

5
@quixoto []є більш надійним, оскільки Arrayйого можна переписати на щось інше. Якщо вам потрібно повторно використовувати Array#slice, корисно це зробити кеш.
Mathias Bynens

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

125

У 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()повертає інший масив як його результат, який стане "перетвореним" масивом, який ви зможете потім використовувати.


Пояснення 🎯 абстрактне пояснення поняття для функцій об’єкта javascript. Тепер ви можете застосувати його для callфункції Array.prototypeака [].prototypeсамостійно.
Сураб

29

Він отримує sliceфункцію з Array. Потім вона викликає цю функцію, але використовуючи результат document.querySelectorAllяк thisоб'єкт замість фактичного масиву.


19

Це техніка перетворення об’єктів, що нагадують масив, у реальні масиви.

Деякі з цих об'єктів включають:

  • arguments у функціях
  • NodeList (пам’ятайте, що їх вміст може змінюватися після їх отримання, тому перетворення їх у масив - це спосіб їх заморозити)
  • Колекції jQuery, також об’єкти jQuery (деякі документи: API , введіть , вивчіть )

Це служить багатьом цілям, наприклад, об'єкти передаються посиланням, тоді як масиви передаються за значенням.

Крім того, зверніть увагу, що перший аргумент тут 0може бути упущений, ретельне пояснення .

Для повноти також існує jQuery.makeArray () .


15

Як це перетворюється 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 Для кращого розуміння нашого сценарію деякі етапи, необхідні для нашого контексту, були ігноровані з оригінального алгоритму виклику та фрагменту .


1
Дуже приємне покрокове пояснення. Дивовижно! Дякую :)
kittu

1
Приємне пояснення.
NaveenDA

7
[].slice.call(document.querySelectorAll('.slide'));

1. The querySelectorAll() method returns all elements in the document that matches a specified selector(s). 

2. The call() method calls a function with a given this value and arguments provided individually.

3. The slice() method returns the selected elements in an array, as a new array object.

  so this line return the array of [object HTMLDivElement]. Here is the six div with classname "slide" so array length will be 6.

<div class="slideshow">

  <div class="slide">
    first slider1
  </div>
  <div class="slide">
    first slider2
  </div>
  <div class="slide">
    first slider3
  </div>
  <div class="slide">
    first slider4
  </div>
  <div class="slide">
    first slider5
  </div>
  <div class="slide">
    first slider6
  </div>

</div>

<script type="text/javascript">

  var arraylist = [].slice.call(document.querySelectorAll('.slide'));

  alert(arraylist);

</script>

4

З ES6: Просто складіть масив за допомогою Array.from (element.children) або Array.from ({length: 5})

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.