Erklärung von [] .slice.call in Javascript?

197

Ich bin auf diese nette Verknüpfung gestoßen, um eine DOM-Knotenliste in ein reguläres Array zu konvertieren, aber ich muss zugeben, ich verstehe nicht ganz, wie es funktioniert:

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

Es beginnt also mit einem leeren Array []und wird dann sliceverwendet, um das Ergebnis von callin ein neues Array umzuwandeln. Ja?

Das bisschen, das ich nicht verstehe, ist das call. Wie wird das document.querySelectorAll('a')von einer NodeList in ein reguläres Array konvertiert ?

Yansky
quelle
5
Array.prototype.slice.call(document.querySelectorAll('a'));ist eine richtige Methode, um den von Ihnen geschriebenen Codeabschnitt zu schreiben.
Vdegenne
4
Übrigens ist die moderne (und intuitiv verständliche) ES6-Methode dafür Array.from. Dies würde beispielsweise dasselbe tun: Array.from (document.querySelectorAll ('a'));
Rugk

Antworten:

158

Was hier passiert ist, dass Sie aufrufen, slice()als ob es eine Funktion der NodeListVerwendung wäre call(). Was slice()tut in diesem Fall ist ein leeres Array zu erstellen, dann Iterierte durch das Objekt es läuft auf (ursprünglich ein Array, ein jetzt NodeList) und halten Sie die Elemente dieses Objekts in das leere Array anhängt es erstellt, die schließlich zurückgeführt wird. Hier ist ein Artikel dazu .

BEARBEITEN:

Es beginnt also mit einem leeren Array [], dann wird Slice verwendet, um das Ergebnis des Aufrufs in ein neues Array umzuwandeln. Ja?

Das ist nicht richtig. [].slicegibt ein Funktionsobjekt zurück. Ein Funktionsobjekt hat eine Funktion, call()die die Funktion aufruft, die den ersten Parameter von call()to zuweist this. Mit anderen Worten, die Funktion denkt, dass sie vom Parameter (der von NodeListzurückgegeben wird document.querySelectorAll('a')) und nicht von einem Array aufgerufen wird .

Max Shawabkeh
quelle
59
Beachten Sie auch hier, dass dies, obwohl es semantisch dem Sprichwort entspricht Array.prototype.slice.call(...), tatsächlich ein Array-Objekt ( []) instanziiert, nur um auf seine Prototyp-Slice-Methode zuzugreifen. Das ist eine verschwendete Instanziierung. Array.prototype.slice.call(...)Stattdessen zu sagen ist sauberer, obwohl Sie Ihrem JS mehrere Zeichen hinzufügen, wenn Sie zählen ...
Ben Zotto
Beachten Sie, dass dies in IE 8 und darunter nur für Array-Objekte funktioniert, sodass Sie NodeLists
Livingston Samuel
5
@quixoto []ist zuverlässiger, da Arrayes zu etwas anderem überschrieben werden könnte. Wenn Sie es wiederverwenden müssen Array#slice, ist es eine gute Idee, es zwischenzuspeichern.
Mathias Bynens
2
Falls jemand nach einer Möglichkeit sucht, dies in IE8 zu tun, lesen Sie
Liam Newmarch
1
Ich habe dieses Muster tatsächlich im Quellcode von backbone.js gesehen: var array = []; var push = array.push; var slice = array.slice; var splice = array.splice;Tut er dies für das Sicherheitsproblem, das @MathiasBynens erwähnt?
Owensmartin
125

In JavaScript können Methoden eines Objekts zur Laufzeit an ein anderes Objekt gebunden werden. Kurz gesagt, mit Javascript kann ein Objekt die Methode eines anderen Objekts "ausleihen":

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'

Mit den Methoden callund applyMethoden von Funktionsobjekten (in JavaScript sind Funktionen auch Objekte) können Sie dies tun. In Ihrem Code könnte man also sagen, dass die NodeList die Slice-Methode eines Arrays ausleiht. .slice()Gibt als Ergebnis ein anderes Array zurück, das zum "konvertierten" Array wird, das Sie dann verwenden können.

Slebetman
quelle
Klicken Sie auf 🎯 Zusammenfassung des abstrakten Konzepts für die Funktionen des Javascript-Objekts. Jetzt können Sie es für die callFunktion von Array.prototypeaka sich [].prototypeselbst anwenden .
Sourabh
29

Es ruft die sliceFunktion von einem ab Array. Diese Funktion wird dann aufgerufen, wobei jedoch das Ergebnis von document.querySelectorAllals thisObjekt anstelle eines tatsächlichen Arrays verwendet wird.

Brian Campbell
quelle
19

Es ist eine Technik, um Array-ähnliche Objekte in echte Arrays umzuwandeln.

Einige dieser Objekte umfassen:

  • arguments in Funktionen
  • NodeList ( Denken Sie daran, dass sich der Inhalt nach dem Abrufen ändern kann. Wenn Sie sie also in ein Array konvertieren, können Sie sie einfrieren.)
  • jQuery-Sammlungen, auch bekannt als jQuery-Objekte (einige Dokumente: API , Typ , Lernen )

Dies dient vielen Zwecken, zum Beispiel werden Objekte als Referenz übergeben, während Arrays als Wert übergeben werden.

Beachten Sie auch, dass das erste Argument 0weggelassen werden kann, eine ausführliche Erklärung hier .

Der Vollständigkeit halber gibt es auch jQuery.makeArray () .

Gras Double
quelle
15

Wie konvertiert das document.querySelectorAll('a')von einem NodeList zu einem regulären Array?

Dies ist der Code, den wir haben,

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

Lass es uns zuerst zerlegen,

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

Schritt: 1 Ausführung der callFunktion

  • Im Inneren callwerden thisArgdie restlichen Argumente an eine Argumentliste angehängt.
  • Jetzt wird die Funktion sliceaufgerufen, indem ihr thisWert als thisArg(Array-ähnliches Objekt stammt von document.querySelector) und mit der Argumentliste gebunden werden . dh] Argument, startdas enthält0

Schritt: 2 Ausführung der sliceinnerhalb von aufgerufenen Funktioncall

  • startwird einer Variablen sals zugewiesen0
  • da endist undefined, this.lengthwird in gespeicherte
  • Ein leeres Array wird in einer Variablen gespeichert a
  • Nachdem Sie die obigen Einstellungen vorgenommen haben, wird die folgende Iteration durchgeführt

    while(s < e) {
      a.push(this[s]);
      s++;
    }
  • Das aufgefüllte Array awird als Ergebnis zurückgegeben.

PS Zum besseren Verständnis unseres Szenarios wurden einige Schritte, die für unseren Kontext erforderlich sind, vom ursprünglichen Algorithmus für Aufruf und Slice ignoriert .

Rajaprabhu Aravindasamy
quelle
1
Sehr schöne Schritt für Schritt Erklärung. Genial! Vielen Dank :)
Kittu
1
Schöne Erklärung.
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>
Ankit Parmar
quelle
4

Von ES6: Erstellen Sie einfach ein Array mit Array.from (element.children) oder Array.from ({length: 5}).

Мони
quelle