Je sais qu'il est utilisé pour faire des arguments un vrai tableau, mais je ne comprends pas ce qui se passe lorsque l'on utilise Array.prototype.slice.call(arguments)
Réponses
Trop de publicités?Ce qui se passe sous le capot, c'est que lorsque .slice()
est appelé normalement, this
est un tableau, et ensuite il itère simplement sur ce tableau, et fait son travail.
Comment this
dans le .slice()
fonction un tableau ? Parce que lorsque vous le faites :
object.method();
...le object
devient automatiquement la valeur de this
dans le method()
. Donc avec :
[1,2,3].slice()
...le [1,2,3]
Le tableau est défini comme la valeur de this
sur .slice()
.
Mais si vous pouviez substituer quelque chose d'autre comme le this
valeur ? Tant que ce que vous substituez a une valeur numérique .length
et un tas de propriétés qui sont des indices numériques, cela devrait fonctionner. Ce type d'objet est souvent appelé un objet de type tableau .
Le site .call()
y .apply()
Les méthodes vous permettent manuellement définir la valeur de this
dans une fonction. Ainsi, si nous définissons la valeur de this
sur .slice()
à un objet de type tableau , .slice()
sera juste supposez il travaille avec un tableau, et fera son travail.
Prenons l'exemple de cet objet ordinaire.
var my_object = {
'0': 'zero',
'1': 'one',
'2': 'two',
'3': 'three',
'4': 'four',
length: 5
};
Il ne s'agit évidemment pas d'un tableau, mais si vous pouvez le définir comme l'élément this
valeur de .slice()
alors cela fonctionnera, parce qu'il ressemble suffisamment à un tableau pour que l'on puisse l'utiliser. .slice()
pour fonctionner correctement.
var sliced = Array.prototype.slice.call( my_object, 3 );
Ejemplo: http://jsfiddle.net/wSvkv/
Comme vous pouvez le voir dans la console, le résultat est conforme à nos attentes :
['three','four'];
Voici donc ce qui se passe lorsque vous définissez un arguments
comme l'objet this
valeur de .slice()
. Parce que arguments
a un .length
et un certain nombre d'indices numériques, .slice()
fait son travail comme s'il s'agissait d'un vrai Array.
Le site arguments
n'est pas réellement une instance d'un tableau, et ne possède aucune des méthodes de tableau. Donc, arguments.slice(...)
ne fonctionnera pas car l'objet arguments ne possède pas la méthode slice.
Les tableaux disposent de cette méthode, et parce que l'élément arguments
est très similaire à un tableau, les deux sont compatibles. Cela signifie que nous pouvons utiliser les méthodes de tableau avec l'objet arguments. Et comme les méthodes de tableau ont été conçues pour les tableaux, elles renverront des tableaux plutôt que d'autres objets arguments.
Alors pourquoi utiliser Array.prototype
? Le site Array
est l'objet à partir duquel nous créons de nouveaux tableaux ( new Array()
), et ces nouveaux tableaux reçoivent des méthodes et des propriétés, comme slice. Ces méthodes sont stockées dans le fichier [Class].prototype
objet. Ainsi, par souci d'efficacité, au lieu d'accéder à la méthode slice par (new Array()).slice.call()
o [].slice.call()
nous l'obtenons directement du prototype. Ainsi, nous n'avons pas besoin d'initialiser un nouveau tableau.
Mais pourquoi devons-nous faire cela en premier lieu ? Eh bien, comme vous l'avez dit, cela convertit un objet arguments en une instance Array. La raison pour laquelle nous utilisons slice, cependant, est plus un "hack" qu'autre chose. La méthode slice prend une tranche d'un tableau, vous l'avez deviné, et renvoie cette tranche sous la forme d'un nouveau tableau. Si vous ne lui passez aucun argument (en dehors de l'objet arguments comme contexte), la méthode slice prendra un morceau complet du "tableau" passé (dans ce cas, l'objet arguments) et le retournera comme un nouveau tableau.
Normalement, l'appel
var b = a.slice();
copiera le tableau a
sur b
. Cependant, nous ne pouvons pas faire
var a = arguments.slice();
parce que arguments
n'est pas un vrai tableau, et ne possède pas de slice
comme méthode. Array.prototype.slice
est le slice
pour les tableaux, et call
exécute la fonction avec this
réglé sur arguments
.
// 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]
C'est parce que, comme Notes du MDN
L'objet arguments n'est pas un tableau. Il est similaire à un tableau, mais il ne possède aucune propriété de tableau, à l'exception de la longueur. Par exemple, il ne possède pas par exemple, il ne possède pas la méthode pop. Cependant, il peut être converti en un véritable tableau :
Ici, nous appelons slice
sur l'objet natif Array
et non sur son mise en œuvre et c'est pourquoi le supplément .prototype
var args = Array.prototype.slice.call(arguments);