So che è usato per rendere gli argomenti un vero array, ma non capisco cosa succede quando si usa Array.prototype.slice.call(arguments)
So che è usato per rendere gli argomenti un vero array, ma non capisco cosa succede quando si usa Array.prototype.slice.call(arguments)
Risposte:
Quello che succede sotto il cofano è che quando .slice()
viene chiamato normalmente, this
è un array e quindi scorre solo su quell'array e fa il suo lavoro.
Come è this
nella .slice()
funzione un array? Perché quando lo fai:
object.method();
... object
diventa automaticamente il valore di this
in method()
. Quindi con:
[1,2,3].slice()
... l' [1,2,3]
array è impostato come valore di this
in .slice()
.
E se potessi sostituire qualcos'altro come this
valore? Finché tutto ciò che sostituisci ha una .length
proprietà numerica e un gruppo di proprietà che sono indici numerici, dovrebbe funzionare. Questo tipo di oggetto viene spesso chiamato un oggetto simile a un array .
I metodi .call()
e .apply()
consentono di impostare manualmente il valore di this
in una funzione. Quindi, se si imposta il valore di this
in .slice()
un array come oggetto , .slice()
sarà solo supporre che sta lavorando con un array, e farà il suo dovere.
Prendi questo semplice oggetto come esempio.
var my_object = {
'0': 'zero',
'1': 'one',
'2': 'two',
'3': 'three',
'4': 'four',
length: 5
};
Ovviamente questo non è un array, ma se è possibile impostarlo come this
valore di .slice()
, allora funzionerà, perché sembra abbastanza un array per .slice()
funzionare correttamente.
var sliced = Array.prototype.slice.call( my_object, 3 );
Esempio: http://jsfiddle.net/wSvkv/
Come puoi vedere nella console, il risultato è quello che ci aspettiamo:
['three','four'];
Questo è ciò che accade quando si imposta un arguments
oggetto come this
valore di .slice()
. Perché arguments
ha una .length
proprietà e un mucchio di indici numerici, .slice()
fa il suo lavoro come se stesse lavorando su un array reale.
Array.prototype.slice
descrizione del metodo.
for-in
affermazione che non garantisce l'ordine. L'algoritmo utilizzato da .slice()
definisce un ordine numerico che inizia con 0
e termina (non inclusivo) con l' .length
oggetto specificato (o Array o altro). Pertanto, l'ordine è garantito per essere coerente in tutte le implementazioni.
var obj = {2:"two", 0:"zero", 1: "one"}
. Se utilizziamo for-in
per enumerare l'oggetto, non vi è alcuna garanzia di ordine. Ma se usiamo for
, siamo in grado di far rispettare manualmente l'ordine: for (var i = 0; i < 3; i++) { console.log(obj[i]); }
. Ora sappiamo che le proprietà dell'oggetto saranno raggiunte nell'ordine numerico crescente che abbiamo definito dal nostro for
ciclo. Questo è quello che .slice()
fa. Non importa se ha un array reale. Inizia da 0
e accede alle proprietà in un ciclo crescente.
L' arguments
oggetto non è in realtà un'istanza di un array e non ha alcun metodo dell'array. Quindi, arguments.slice(...)
non funzionerà perché l'oggetto argomenti non ha il metodo slice.
Gli array hanno questo metodo e poiché l' arguments
oggetto è molto simile a un array, i due sono compatibili. Ciò significa che possiamo usare metodi array con l'oggetto argomenti. E poiché i metodi array sono stati creati pensando alle matrici, restituiranno matrici anziché altri oggetti argomento.
Quindi perché usare Array.prototype
? Il Array
è l'oggetto di creiamo nuovi array da ( new Array()
), e questi nuovi array sono passati metodi e proprietà, come fetta. Questi metodi sono memorizzati [Class].prototype
nell'oggetto. Quindi, per motivi di efficienza, invece di accedere al metodo slice da (new Array()).slice.call()
o [].slice.call()
, lo otteniamo direttamente dal prototipo. Questo è quindi non è necessario inizializzare un nuovo array.
Ma perché dobbiamo farlo prima di tutto? Bene, come hai detto, converte un oggetto argomenti in un'istanza di matrice. Il motivo per cui usiamo slice, tuttavia, è più un "hack" che altro. Il metodo slice prenderà una sezione, hai indovinato, di una matrice e restituirà quella fetta come nuova matrice. Passandogli nessun argomento (oltre all'oggetto argomenti come suo contesto), il metodo slice prende un pezzo completo della "matrice" passata (in questo caso, l'oggetto argomenti) e lo restituisce come una nuova matrice.
Normalmente, chiamando
var b = a.slice();
copierà l'array a
in b
. Tuttavia, non possiamo farlo
var a = arguments.slice();
perché arguments
non è un array reale e non ha slice
come metodo. Array.prototype.slice
è la slice
funzione per le matrici ed call
esegue la funzione con this
set su arguments
.
prototype
? non è slice
un Array
metodo nativo ?
Array
è una funzione di costruzione e la "classe" corrispondente è Array.prototype
. Puoi anche usare[].slice
slice
è un metodo di ogni Array
istanza, ma non la Array
funzione di costruzione. Utilizzi prototype
per accedere ai metodi delle istanze teoriche di un costruttore.
Innanzitutto, dovresti leggere come funziona l'invocazione della funzione in JavaScript . Sospetto che da solo sia sufficiente rispondere alla tua domanda. Ma ecco un riassunto di ciò che sta accadendo:
Array.prototype.slice
estrae il metodo da 's prototipo . Ma chiamarlo direttamente non funzionerà, poiché è un metodo (non una funzione) e quindi richiede un contesto (un oggetto chiamante ), altrimenti verrebbe lanciato .slice
Array
this
Uncaught TypeError: Array.prototype.slice called on null or undefined
Il call()
metodo consente di specificare il contesto di un metodo, fondamentalmente rendendo equivalenti queste due chiamate:
someObject.slice(1, 2);
slice.call(someObject, 1, 2);
Tranne il primo richiede che il slice
metodo esista nella someObject
catena di prototipi (come fa per Array
), mentre il secondo consente il contesto (someObject
) di essere passato manualmente al metodo.
Inoltre, quest'ultimo è l'abbreviazione di:
var slice = Array.prototype.slice;
slice.call(someObject, 1, 2);
Che è lo stesso di:
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 (argomenti) è il vecchio modo di convertire un argomento in un array.
In ECMAScript 2015, è possibile utilizzare Array.from o l'operatore di diffusione:
let args = Array.from(arguments);
let args = [...arguments];
È perché, come osserva MDN
L'oggetto argomenti non è un array. È simile a un array, ma non ha proprietà dell'array tranne la lunghezza. Ad esempio, non ha il metodo pop. Tuttavia, può essere convertito in un array reale:
Qui stiamo invocando slice
l'oggetto nativo Array
e non la sua implementazione e questo è il motivo per cui extra.prototype
var args = Array.prototype.slice.call(arguments);
Non dimenticare che una base di basso livello di questo comportamento è il casting del tipo integrato nel motore JS.
Slice prende semplicemente l'oggetto (grazie alla proprietà argomenti.length esistente) e restituisce un oggetto array lanciato dopo aver eseguito tutte le operazioni su di esso.
Le stesse logiche che puoi provare se provi a trattare il metodo String con un valore INT:
String.prototype.bold.call(11); // returns "<b>11</b>"
E questo spiega la dichiarazione sopra.
Usa il slice
metodo che hanno gli array e lo chiama con il this
fatto che è l' arguments
oggetto. Ciò significa che lo chiama come se avessi arguments.slice()
assunto arguments
un simile metodo.
La creazione di una sezione senza argomenti richiederà semplicemente tutti gli elementi, quindi copia semplicemente gli elementi arguments
in un array.
Supponiamo che tu abbia: function.apply(thisArg, argArray )
Il metodo apply invoca una funzione, passando l'oggetto che sarà associato a questo e un array opzionale di argomenti.
Il metodo slice () seleziona una parte di un array e restituisce il nuovo array.
Pertanto, quando si chiama Array.prototype.slice.apply(arguments, [0])
il metodo slice dell'array, viene richiamato (bind) sugli argomenti.
Forse un po 'in ritardo, ma la risposta a tutto questo casino è che call () è usato in JS per ereditarietà. Se confrontiamo questo con Python o PHP, ad esempio, call viene usato rispettivamente come super (). init () o parent :: _ construct ().
Questo è un esempio del suo utilizzo che chiarisce tutto:
function Teacher(first, last, age, gender, interests, subject) {
Person.call(this, first, last, age, gender, interests);
this.subject = subject;
}
Riferimento: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Inheritance
quando .slice () viene chiamato normalmente, si tratta di un array, quindi esegue l'iterazione su tale array e fa il suo lavoro.
//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"]
Sto solo scrivendo questo per ricordare a me stesso ...
Array.prototype.slice.call(arguments);
== Array.prototype.slice(arguments[1], arguments[2], arguments[3], ...)
== [ arguments[1], arguments[2], arguments[3], ... ]
O semplicemente usa questa pratica funzione $ A per trasformare la maggior parte delle cose in un array.
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);
}
esempio di utilizzo ...
function test() {
$A( arguments ).forEach( function(arg) {
console.log("Argument: " + arg);
});
}