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 è thisnella .slice()funzione un array? Perché quando lo fai:
object.method();
... objectdiventa automaticamente il valore di thisin method(). Quindi con:
[1,2,3].slice()
... l' [1,2,3]array è impostato come valore di thisin .slice().
E se potessi sostituire qualcos'altro come thisvalore? Finché tutto ciò che sostituisci ha una .lengthproprietà 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 thisin una funzione. Quindi, se si imposta il valore di thisin .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 thisvalore 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 argumentsoggetto come thisvalore di .slice(). Perché argumentsha una .lengthproprietà e un mucchio di indici numerici, .slice()fa il suo lavoro come se stesse lavorando su un array reale.
Array.prototype.slicedescrizione del metodo.
for-inaffermazione che non garantisce l'ordine. L'algoritmo utilizzato da .slice()definisce un ordine numerico che inizia con 0e termina (non inclusivo) con l' .lengthoggetto 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-inper 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 forciclo. Questo è quello che .slice()fa. Non importa se ha un array reale. Inizia da 0e accede alle proprietà in un ciclo crescente.
L' argumentsoggetto 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' argumentsoggetto è 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].prototypenell'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é argumentsnon è un array reale e non ha slicecome metodo. Array.prototype.sliceè la slicefunzione per le matrici ed callesegue la funzione con thisset su arguments.
prototype? non è sliceun Arraymetodo nativo ?
Arrayè una funzione di costruzione e la "classe" corrispondente è Array.prototype. Puoi anche usare[].slice
sliceè un metodo di ogni Arrayistanza, ma non la Arrayfunzione di costruzione. Utilizzi prototypeper 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.sliceestrae 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 ArraythisUncaught 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 slicemetodo esista nella someObjectcatena 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 slicel'oggetto nativo Arraye 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 slicemetodo che hanno gli array e lo chiama con il thisfatto che è l' argumentsoggetto. Ciò significa che lo chiama come se avessi arguments.slice()assunto argumentsun simile metodo.
La creazione di una sezione senza argomenti richiederà semplicemente tutti gli elementi, quindi copia semplicemente gli elementi argumentsin 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);
});
}