529 Stimmen

Wie funktioniert der "Array.prototype.slice.call"?

Ich weiß, dass es verwendet wird, um arguments eine echte Array aber ich verstehe nicht, was passiert, wenn ich Array.prototype.slice.call(arguments); .

927voto

user113716 Punkte 309387

Was unter der Haube passiert ist, dass wenn .slice() normal aufgerufen wird, this ist ein Array, und dann iteriert es einfach über dieses Array und erledigt seine Arbeit.

Wie ist this im .slice() Funktion ein Array? Denn wenn Sie das tun:

object.method();

...die object wird automatisch der Wert von this im method() . Also mit:

[1,2,3].slice()

...die [1,2,3] Array wird als der Wert von this en .slice() .


Aber was wäre, wenn Sie etwas anderes als die this Wert? Solange das, was Sie ersetzen, einen numerischen Wert hat .length Eigenschaft und eine Reihe von Eigenschaften, die numerische Indizes sind, sollte es funktionieren. Diese Art von Objekt wird oft als array-ähnliches Objekt .

El .call() y .apply() Methoden können Sie manuell setzen den Wert von this in einer Funktion. Wenn wir also den Wert von this en .slice() zu einer array-ähnliches Objekt , .slice() wird nur annehmen es arbeitet mit einem Array, und wird sein Ding machen.

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 die this Wert von .slice() dann wird es einfach funktionieren, weil es wie ein Array aussieht und .slice() richtig zu funktionieren.

var sliced = Array.prototype.slice.call( my_object, 3 );

Beispiel: http://jsfiddle.net/wSvkv/

Wie Sie in der Konsole sehen können, ist das Ergebnis das, was wir erwarten:

['three','four'];

Das passiert also, wenn Sie eine arguments Objekt als this Wert von .slice() . Denn arguments hat eine .length Eigenschaft und eine Reihe von numerischen Indizes, .slice() geht einfach seiner Arbeit nach, als ob es an einem echten Array arbeiten würde.

98voto

Ben Punkte 4889

El arguments Objekt ist nicht wirklich eine Instanz eines Arrays und verfügt über keine der Array-Methoden. Also, arguments.slice(...) funktioniert nicht, da das Argumente-Objekt nicht über die Slice-Methode verfügt.

Arrays haben diese Methode, und weil die arguments Objekt ist einem Array sehr ähnlich, die beiden sind kompatibel. Das bedeutet, dass wir Array-Methoden mit dem Argument Objekt verwenden können. Und da Array-Methoden mit Blick auf Arrays entwickelt wurden, geben sie eher Arrays als andere Argumentobjekte zurück.

Warum also die Array.prototype ? Die Array ist das Objekt, aus dem wir neue Arrays erstellen ( new Array() ), und diesen neuen Arrays werden Methoden und Eigenschaften wie slice übergeben. Diese Methoden werden in der [Class].prototype Objekt. Aus Gründen der Effizienz sollte der Zugriff auf die Slice-Methode also nicht über (new Array()).slice.call() o [].slice.call() Wir holen es uns einfach direkt vom Prototyp. Dies ist so, dass wir nicht ein neues Array initialisieren müssen.

Aber warum müssen wir das überhaupt tun? Nun, wie Sie schon sagten, wird damit ein Argument-Objekt in eine Array-Instanz umgewandelt. Der Grund, warum wir slice verwenden, ist jedoch mehr ein "Hack" als alles andere. Die slice-Methode nimmt einen, Sie ahnen es, Ausschnitt eines Arrays und gibt diesen Ausschnitt als neues Array zurück. Wenn man ihr keine Argumente übergibt (außer dem arguments-Objekt als Kontext), nimmt die slice-Methode einen kompletten Teil des übergebenen "Arrays" (in diesem Fall das arguments-Objekt) und gibt ihn als neues Array zurück.

51voto

Delan Azabani Punkte 76072

Normalerweise wird der Aufruf

var b = a.slice();

kopiert das Array a in b . Allerdings können wir nicht tun

var a = arguments.slice();

denn arguments hat keine slice als Methode (es handelt sich nicht um ein echtes Array).

Array.prototype.slice es el slice Funktion für Arrays. .call läuft dies slice Funktion, mit der this Wert eingestellt auf arguments .

29voto

Array.prototype.slice.call(arguments) ist der altmodische Weg, um ein Argument in ein Array umzuwandeln.

In ECMAScript 2015 können Sie Array.from oder den Spread-Operator verwenden:

let args = Array.from(arguments);

let args = [...arguments];

25voto

Marco Roy Punkte 3081

Zuerst sollten Sie lesen wie Funktionsaufrufe in JavaScript funktionieren . Ich vermute, das allein reicht aus, um Ihre Frage zu beantworten. Aber hier ist eine Zusammenfassung dessen, was passiert:

Array.prototype.slice extrahiert die slice Methode von Array 's Prototyp . Aber direkt anrufen wird nicht funktionieren, da es sich um eine Methode (nicht um eine Funktion) handelt und erfordert daher einen Kontext (ein aufrufendes Objekt), this ), sonst würde es Uncaught TypeError: Array.prototype.slice called on null or undefined .

El call() Methode können Sie den Kontext einer Methode angeben, was diese beiden Aufrufe im Grunde gleichwertig macht:

someObject.slice(1, 2);
slice.call(someObject, 1, 2);

Außer bei ersterem muss die slice Methode zu existieren someObject Prototypenkette (wie bei Array ), während letztere den Kontext ( someObject ), die manuell an die Methode übergeben werden müssen.

Letzteres ist auch eine Abkürzung für:

var slice = Array.prototype.slice;
slice.call(someObject, 1, 2);

Das ist dasselbe wie:

Array.prototype.slice.call(someObject, 1, 2);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X