Wyjaśnienie [] .slice.call w javascript?


197

Natknąłem się na ten zgrabny skrót do konwersji DOM NodeList w zwykłą tablicę, ale muszę przyznać, że nie do końca rozumiem, jak to działa:

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

Więc zaczyna się od pustej tablicy [], a następnie slicesłuży do konwersji wyniku callna nową tablicę, tak?

Nie rozumiem tylko tego call. Jak to się przekształca document.querySelectorAll('a')z NodeList do zwykłej tablicy?


5
Array.prototype.slice.call(document.querySelectorAll('a'));to właściwy sposób na napisanie fragmentu kodu, który napisałeś.
— vdegenne,

4
BTW, nowoczesna (i intuicyjnie zrozumiała) metoda ES6 dla tego samego jest Array.from. Tak więc np. Zrobiłoby to samo: Array.from (document.querySelectorAll ('a'));
— rugk

Odpowiedzi:


158

To, co się tutaj dzieje, polega na tym, że dzwonisz slice()tak, jakby to była funkcja NodeListużywania call(). Co slice()robi w tym przypadku jest utworzyć pustą tablicę, następnie iterację obiektu to działa (pierwotnie na tablicy, teraz NodeList) i utrzymać dołączanie elementów tego obiektu do pustej tablicy utworzony, który ostatecznie powrócił. Oto artykuł na ten temat .

EDYTOWAĆ:

Zaczyna się więc od pustej tablicy [], a następnie kawałek służy do konwersji wyniku wywołania na nową tablicę, tak?

To nie tak. [].slicezwraca obiekt funkcji. Obiekt funkcji ma funkcję, call()która wywołuje funkcję przypisującą pierwszy parametr call()do this; innymi słowy, sprawiając, że funkcja myśli, że jest wywoływana z parametru ( NodeListzwróconego przez document.querySelectorAll('a')), a nie z tablicy.


59
Zauważ też, że chociaż jest to semantycznie równoważne z powiedzeniem Array.prototype.slice.call(...), w rzeczywistości tworzy on obiekt tablicowy ( []) tylko w celu uzyskania dostępu do jego metody wycinania prototypów. To zmarnowana instancja. Mówienie Array.prototype.slice.call(...)zamiast tego jest czystsze, chociaż dodajesz kilka znaków do JS, jeśli liczysz ...
— Ben Zotto

Zauważ, że działa to w IE 8 i niższych tylko na obiektach Array, więc nie będziesz w stanie klonować NodeLists
— Livingston Samuel

5
@quixoto []jest bardziej niezawodny, ponieważ Arraymożna go zastąpić czymś innym. Jeśli musisz użyć ponownie Array#slice, dobrze jest buforować.
— Mathias Bynens

2
Jeśli ktoś inny szuka sposobu, aby to zrobić w IE8, sprawdź to pytanie stackoverflow.com/questions/3199588/...
— Liam Newmarch,

1
W rzeczywistości widziałem ten wzorzec pojawiający się w kodzie źródłowym backbone.js: var array = []; var push = array.push; var slice = array.slice; var splice = array.splice;Czy robi to w związku z kwestią bezpieczeństwa wspomnianą przez @MathiasBynens?
— owensmartin

125

W JavaScript metody obiektu można powiązać z innym obiektem w czasie wykonywania. W skrócie, javascript pozwala obiektowi „pożyczyć” metodę innego obiektu:

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'

Te calli applymetody obiektów funkcyjnych (w JavaScript, funkcje są obiektami, jak również) pozwala to zrobić. Zatem w kodzie można powiedzieć, że NodeList pożycza metodę plasterka tablicy. .slice()zwraca inną tablicę jako wynik, która stanie się „skonwertowaną” tablicą, z której będziesz mógł korzystać.


Bang on 🎯 abstrakcyjne wyjaśnienie koncepcji funkcji obiektu javascript. Teraz możesz zastosować go do callfunkcji Array.prototypeaka [].prototypesiebie.
— Sourabh

29

Pobiera slicefunkcję z Array. Następnie wywołuje tę funkcję, ale używając wyniku document.querySelectorAlljako thisobiektu zamiast rzeczywistej tablicy.


19

Jest to technika przekształcania obiektów tablicowych w prawdziwe tablice.

Niektóre z tych obiektów obejmują:

  • arguments w funkcjach
  • NodeList (pamiętaj, że ich zawartość może się zmienić po pobraniu! Więc konwersja ich do tablicy jest sposobem na ich zamrożenie)
  • Kolekcje jQuery, czyli obiekty jQuery (niektóre dokumenty: API , typ , nauka )

Służy to wielu celom, na przykład obiekty są przekazywane przez odniesienie, a tablice są przekazywane przez wartość.

Zauważ też, że pierwszy argument 0można pominąć, dokładne wyjaśnienie tutaj .

Dla zapewnienia kompletności istnieje również jQuery.makeArray () .


15

Jak to się przekształca document.querySelectorAll('a')z NodeList tablicy na zwykłą?

To jest kod, który mamy,

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

Najpierw go zdemontujmy,

  []    // 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'

Krok: 1 Wykonanie callfunkcji

  • Wewnątrz call, poza tym thisArg, pozostałe argumenty zostaną dołączone do listy argumentów.
  • Teraz funkcja slicezostanie wywołana przez powiązanie jej thiswartości jako thisArg(pochodzi z obiektu typu tablicowego document.querySelector) i listy argumentów. ie] argument, startktóry zawiera0

Krok: 2 Wywołanie slicefunkcji wywołanej wewnątrzcall

  • startzostanie przypisany do zmiennej sjako0
  • ponieważ endjest undefined, this.lengthbędzie przechowywany we
  • pusta tablica będzie przechowywana w zmiennej a
  • Po wprowadzeniu powyższych ustawień nastąpi następująca iteracja

    while(s < e) {
      a.push(this[s]);
      s++;
    }
  • ajako wynik zostanie zwrócona wypełniona tablica .

PS Aby lepiej zrozumieć nasz scenariusz, niektóre kroki niezbędne dla naszego kontekstu zostały zignorowane z oryginalnego algorytmu call and slice .


1
Bardzo ładne wyjaśnienie krok po kroku. Niesamowite! Dziękuję :)
— Kittu

1
Niezłe wyjaśnienie.
— 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

Z ES6: Po prostu stwórz tablicę za pomocą Array.from (element.children) lub Array.from ({length: 5})

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.