Ich weiß, dass es verwendet wird, um Argumente zu einem echten Array zu machen, aber ich verstehe nicht, was bei der Verwendung passiert Array.prototype.slice.call(arguments)
Ich weiß, dass es verwendet wird, um Argumente zu einem echten Array zu machen, aber ich verstehe nicht, was bei der Verwendung passiert Array.prototype.slice.call(arguments)
Antworten:
Was unter der Haube passiert, ist, dass, wenn .slice()
es normal aufgerufen wird, this
es sich um ein Array handelt, das dann nur über dieses Array iteriert und seine Arbeit erledigt.
Wie ist this
in der .slice()
Funktion ein Array? Denn wenn Sie dies tun:
object.method();
... das wird object
automatisch zum Wert von this
in der method()
. Also mit:
[1,2,3].slice()
... das [1,2,3]
Array wird als Wert von this
in gesetzt .slice()
.
Aber was wäre, wenn Sie etwas anderes als this
Wert ersetzen könnten ? Solange alles, was Sie ersetzen, eine numerische .length
Eigenschaft und eine Reihe von Eigenschaften hat, die numerische Indizes sind, sollte es funktionieren. Dieser Objekttyp wird häufig als Array-ähnliches Objekt bezeichnet .
Mit den Methoden .call()
und .apply()
können Sie den Wert von in einer Funktion manuell festlegen this
. Wenn wir also den Wert von this
in .slice()
auf ein Array-ähnliches Objekt setzen , .slice()
wird einfach angenommen, dass es mit einem Array funktioniert, und es wird seine Sache tun.
Nehmen Sie dieses einfache Objekt als Beispiel.
var my_object = {
'0': 'zero',
'1': 'one',
'2': 'two',
'3': 'three',
'4': 'four',
length: 5
};
Dies ist offensichtlich kein Array, aber wenn Sie es als this
Wert festlegen können, .slice()
funktioniert es einfach, da es wie ein Array aussieht .slice()
, um ordnungsgemäß zu funktionieren.
var sliced = Array.prototype.slice.call( my_object, 3 );
Beispiel: http://jsfiddle.net/wSvkv/
Wie Sie in der Konsole sehen können, erwarten wir folgendes Ergebnis:
['three','four'];
Dies passiert also, wenn Sie ein arguments
Objekt als this
Wert von festlegen .slice()
. Da arguments
es eine .length
Eigenschaft und eine Reihe von numerischen Indizes hat, .slice()
geht es einfach so, als würde es an einem echten Array arbeiten.
Array.prototype.slice
Methodenbeschreibung.
for-in
Aussage, die keine Ordnung garantiert. Der von .slice()
definierte Algorithmus definiert eine numerische Reihenfolge, die 0
mit dem .length
des angegebenen Objekts (oder Arrays oder was auch immer) beginnt und damit endet (nicht inklusive ). Somit ist die Reihenfolge für alle Implementierungen garantiert konsistent.
var obj = {2:"two", 0:"zero", 1: "one"}
. Wenn wir for-in
das Objekt aufzählen, gibt es keine Garantie für die Bestellung. Wenn wir jedoch verwenden for
, können wir die Reihenfolge manuell erzwingen : for (var i = 0; i < 3; i++) { console.log(obj[i]); }
. Jetzt wissen wir, dass die Eigenschaften des Objekts in aufsteigender numerischer Reihenfolge erreicht werden, die wir durch unsere for
Schleife definiert haben . Das .slice()
macht es. Es ist egal, ob es ein tatsächliches Array hat. Es beginnt nur bei 0
und greift in einer aufsteigenden Schleife auf Eigenschaften zu.
Das arguments
Objekt ist eigentlich keine Instanz eines Arrays und verfügt über keine der Array-Methoden. Funktioniert also arguments.slice(...)
nicht, da das Argumentobjekt nicht über die Slice-Methode verfügt.
Arrays haben diese Methode, und da das arguments
Objekt einem Array sehr ähnlich ist, sind beide kompatibel. Dies bedeutet, dass wir Array-Methoden mit dem Argument-Objekt verwenden können. Und da Array-Methoden mit Blick auf Arrays erstellt wurden, geben sie eher Arrays als andere Argumentobjekte zurück.
Warum also verwenden Array.prototype
? Das Array
ist das Objekt, aus dem wir neue Arrays erstellen ( new Array()
), und diese neuen Arrays sind übergebene Methoden und Eigenschaften wie Slice. Diese Methoden werden im [Class].prototype
Objekt gespeichert . Aus Effizienzgründen erhalten wir die Slice-Methode nicht direkt von (new Array()).slice.call()
oder [].slice.call()
, sondern direkt vom Prototyp. Auf diese Weise müssen wir kein neues Array initialisieren.
Aber warum müssen wir das überhaupt tun? Nun, wie Sie sagten, konvertiert es ein Argumentobjekt in eine Array-Instanz. Der Grund, warum wir Slice verwenden, ist jedoch eher ein "Hack" als alles andere. Die Slice-Methode nimmt ein Slice eines Arrays und gibt dieses Slice als neues Array zurück. Wenn keine Argumente an das Objekt übergeben werden (außer dem Argumentobjekt als Kontext), nimmt die Slice-Methode einen vollständigen Teil des übergebenen "Arrays" (in diesem Fall des Argumentobjekts) und gibt es als neues Array zurück.
Normalerweise anrufen
var b = a.slice();
kopiert das Array a
in b
. Das können wir jedoch nicht
var a = arguments.slice();
weil arguments
es kein echtes Array ist und keine slice
Methode hat. Array.prototype.slice
ist die slice
Funktion für Arrays und call
führt die Funktion mit this
set to aus arguments
.
prototype
? ist keine slice
native Array
Methode?
Array
eine Konstruktorfunktion ist und die entsprechende "Klasse" ist Array.prototype
. Sie können auch verwenden[].slice
slice
ist eine Methode für jede Array
Instanz, jedoch nicht die Array
Konstruktorfunktion. Sie verwenden, prototype
um auf Methoden der theoretischen Instanzen eines Konstruktors zuzugreifen.
Zunächst sollten Sie lesen, wie der Funktionsaufruf in JavaScript funktioniert . Ich vermute, dass allein genug ist, um Ihre Frage zu beantworten. Aber hier ist eine Zusammenfassung dessen, was passiert:
Array.prototype.slice
extrahiert die Methode aus dem Prototyp . Ein direkter Aufruf funktioniert jedoch nicht, da es sich um eine Methode (keine Funktion) handelt und daher einen Kontext (ein aufrufendes Objekt ) erfordert , da es sonst ausgelöst wird .slice
Array
this
Uncaught TypeError: Array.prototype.slice called on null or undefined
Mit dieser call()
Methode können Sie den Kontext einer Methode angeben, sodass diese beiden Aufrufe im Wesentlichen gleichwertig sind:
someObject.slice(1, 2);
slice.call(someObject, 1, 2);
Mit der Ausnahme, dass Ersteres erfordert, dass die slice
Methode in someObject
der Prototypenkette vorhanden ist (wie dies auch der Fall ist Array
), während Letzteres die someObject
manuelle Übergabe des Kontextes ( ) an die Methode ermöglicht.
Letzteres ist auch die Abkürzung für:
var slice = Array.prototype.slice;
slice.call(someObject, 1, 2);
Welches ist das gleiche wie:
Array.prototype.slice.call(someObject, 1, 2);
// We can apply `slice` from `Array.prototype`:
Array.prototype.slice.call([]); //-> []
// Since `slice` is available on an array's prototype chain,
'slice' in []; //-> true
[].slice === Array.prototype.slice; //-> true
// … we can just invoke it directly:
[].slice(); //-> []
// `arguments` has no `slice` method
'slice' in arguments; //-> false
// … but we can apply it the same way:
Array.prototype.slice.call(arguments); //-> […]
// In fact, though `slice` belongs to `Array.prototype`,
// it can operate on any array-like object:
Array.prototype.slice.call({0: 1, length: 1}); //-> [1]
Array.prototype.slice.call (Argumente) ist die altmodische Methode, um Argumente in ein Array zu konvertieren.
In ECMAScript 2015 können Sie Array.from oder den Spread-Operator verwenden:
let args = Array.from(arguments);
let args = [...arguments];
Es liegt daran, wie MDN feststellt
Das Argumentobjekt ist kein Array. Es ähnelt einem Array, hat jedoch keine Array-Eigenschaften außer der Länge. Zum Beispiel hat es nicht die Pop-Methode. Es kann jedoch in ein reales Array konvertiert werden:
Hier rufen wir slice
das native Objekt auf Array
und nicht dessen Implementierung und deshalb das Extra.prototype
var args = Array.prototype.slice.call(arguments);
Vergessen Sie nicht, dass eine grundlegende Grundlage dieses Verhaltens das Typ-Casting ist, das vollständig in die JS-Engine integriert ist.
Slice nimmt nur ein Objekt (dank der vorhandenen Eigenschaft arguments.length) und gibt ein Array-Objekt zurück, das nach Ausführung aller Operationen umgewandelt wurde.
Dieselbe Logik, die Sie testen können, wenn Sie versuchen, die String-Methode mit einem INT-Wert zu behandeln:
String.prototype.bold.call(11); // returns "<b>11</b>"
Und das erklärt die obige Aussage.
Es verwendet die slice
Methode, die Arrays haben, und ruft sie mit this
dem arguments
Objekt auf. Dies bedeutet, dass es so heißt, als hätten Sie arguments.slice()
angenommenarguments
eine solche Methode gibt.
Wenn Sie ein Slice ohne Argumente erstellen, werden einfach alle Elemente übernommen, sodass die Elemente einfach arguments
in ein Array kopiert werden .
Nehmen wir an, Sie haben: function.apply(thisArg, argArray )
Die Methode apply ruft eine Funktion auf und übergibt das daran gebundene Objekt und ein optionales Array von Argumenten.
Die Slice () -Methode wählt einen Teil eines Arrays aus und gibt das neue Array zurück.
Wenn Sie also Array.prototype.slice.apply(arguments, [0])
das Array aufrufen, wird die Slice-Methode für Argumente aufgerufen (bind).
Vielleicht etwas spät, aber die Antwort auf all dieses Durcheinander ist, dass call () in JS für die Vererbung verwendet wird. Wenn wir dies zum Beispiel mit Python oder PHP vergleichen, wird call jeweils als super () verwendet. init () oder parent :: _ construct ().
Dies ist ein Beispiel für seine Verwendung, das alles verdeutlicht:
function Teacher(first, last, age, gender, interests, subject) {
Person.call(this, first, last, age, gender, interests);
this.subject = subject;
}
Referenz: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Inheritance
Wenn .slice () normal aufgerufen wird, handelt es sich um ein Array. Anschließend wird das Array einfach durchlaufen und seine Arbeit erledigt.
//ARGUMENTS
function func(){
console.log(arguments);//[1, 2, 3, 4]
//var arrArguments = arguments.slice();//Uncaught TypeError: undefined is not a function
var arrArguments = [].slice.call(arguments);//cp array with explicity THIS
arrArguments.push('new');
console.log(arrArguments)
}
func(1,2,3,4)//[1, 2, 3, 4, "new"]
Ich schreibe das nur, um mich daran zu erinnern ...
Array.prototype.slice.call(arguments);
== Array.prototype.slice(arguments[1], arguments[2], arguments[3], ...)
== [ arguments[1], arguments[2], arguments[3], ... ]
Oder verwenden Sie einfach diese praktische Funktion $ A , um die meisten Dinge in ein Array zu verwandeln.
function hasArrayNature(a) {
return !!a && (typeof a == "object" || typeof a == "function") && "length" in a && !("setInterval" in a) && (Object.prototype.toString.call(a) === "[object Array]" || "callee" in a || "item" in a);
}
function $A(b) {
if (!hasArrayNature(b)) return [ b ];
if (b.item) {
var a = b.length, c = new Array(a);
while (a--) c[a] = b[a];
return c;
}
return Array.prototype.slice.call(b);
}
Beispiel Verwendung ...
function test() {
$A( arguments ).forEach( function(arg) {
console.log("Argument: " + arg);
});
}