Je sais qu'il est utilisé pour faire des arguments un vrai tableau, mais je ne comprends pas ce qui se passe lors de l'utilisation Array.prototype.slice.call(arguments)
Je sais qu'il est utilisé pour faire des arguments un vrai tableau, mais je ne comprends pas ce qui se passe lors de l'utilisation Array.prototype.slice.call(arguments)
Réponses:
Ce qui se passe sous le capot, c'est que lorsqu'il .slice()
est appelé normalement, this
est un tableau, puis il itère simplement sur ce tableau et fait son travail.
Comment est this
dans la .slice()
fonction un tableau? Parce que quand 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]
tableau est défini comme la valeur de this
in .slice()
.
Mais que se passe-t-il si vous pouvez remplacer quelque chose d'autre par la this
valeur? Tant que tout ce que vous remplacez a une .length
propriété numérique et un tas de propriétés qui sont des indices numériques, cela devrait fonctionner. Ce type d'objet est souvent appelé objet de type tableau .
Les méthodes .call()
et .apply()
vous permettent de définir manuellement la valeur de this
dans une fonction. Donc, si nous définissons la valeur de this
in .slice()
dans un objet de type tableau , supposerons.slice()
simplement qu'il fonctionne avec un tableau et fera son travail.
Prenez cet objet simple comme exemple.
var my_object = {
'0': 'zero',
'1': 'one',
'2': 'two',
'3': 'three',
'4': 'four',
length: 5
};
Ce n'est évidemment pas un tableau, mais si vous pouvez le définir comme this
valeur de .slice()
, cela fonctionnera simplement, car il ressemble suffisamment à un tableau pour .slice()
fonctionner correctement.
var sliced = Array.prototype.slice.call( my_object, 3 );
Exemple: http://jsfiddle.net/wSvkv/
Comme vous pouvez le voir dans la console, le résultat est ce que nous attendons:
['three','four'];
C'est donc ce qui se produit lorsque vous définissez un arguments
objet comme this
valeur de .slice()
. Parce qu'il arguments
a une .length
propriété et un tas d'index numériques, .slice()
va juste sur son travail comme s'il travaillait sur un vrai tableau.
Array.prototype.slice
description de la méthode.
for-in
déclaration qui ne garantit pas l'ordre. L'algorithme utilisé par .slice()
définit un ordre numérique commençant par 0
et se terminant (non inclus) par l' .length
objet donné (ou Array ou autre). Il est donc garanti que l'ordre est cohérent dans toutes les implémentations.
var obj = {2:"two", 0:"zero", 1: "one"}
. Si nous utilisons for-in
pour énumérer l'objet, il n'y a aucune garantie d'ordre. Mais si nous utilisons for
, nous pouvons appliquer manuellement l'ordre: for (var i = 0; i < 3; i++) { console.log(obj[i]); }
. Nous savons maintenant que les propriétés de l'objet seront atteintes dans l'ordre numérique croissant que nous avons défini par notre for
boucle. Voilà ce qui .slice()
fait. Il ne se soucie pas d'avoir un véritable tableau. Il commence juste à 0
et accède aux propriétés dans une boucle ascendante.
L' arguments
objet n'est pas réellement une instance d'un tableau et n'a aucune des méthodes de tableau. Donc, arguments.slice(...)
cela ne fonctionnera pas car l'objet arguments n'a pas la méthode slice.
Les tableaux ont cette méthode, et parce que l' arguments
objet est très similaire à un tableau, les deux sont compatibles. Cela signifie que nous pouvons utiliser des méthodes de tableau avec l'objet arguments. Et puisque les méthodes de tableau ont été construites avec des tableaux à l'esprit, elles renverront des tableaux plutôt que d'autres objets d'argument.
Alors pourquoi l'utiliser Array.prototype
? C'est Array
l'objet à partir duquel nous créons de nouveaux tableaux à partir de ( new Array()
), et ces nouveaux tableaux sont des méthodes et des propriétés transmises, comme slice. Ces méthodes sont stockées dans l' [Class].prototype
objet. Donc, pour des raisons d'efficacité, au lieu d'accéder à la méthode de tranche par (new Array()).slice.call()
ou [].slice.call()
, nous l'obtenons directement à partir du prototype. C'est ainsi que nous n'avons pas à initialiser un nouveau tableau.
Mais pourquoi devons-nous le faire en premier lieu? Eh bien, comme vous l'avez dit, il convertit un objet arguments en une instance Array. Cependant, la raison pour laquelle nous utilisons la tranche est plus un "hack" qu'autre chose. La méthode slice prendra une, vous l'avez deviné, une tranche d'un tableau et retournera cette tranche comme un nouveau tableau. Le fait de ne lui passer aucun argument (en plus de l'objet arguments comme contexte) amène la méthode slice à prendre un morceau complet du "tableau" passé (dans ce cas, l'objet arguments) et à le renvoyer comme un nouveau tableau.
Normalement, appeler
var b = a.slice();
copiera le tableau a
dans b
. Cependant, nous ne pouvons pas faire
var a = arguments.slice();
car arguments
n'est pas un vrai tableau et n'a pas slice
de méthode. Array.prototype.slice
est la slice
fonction des tableaux et call
exécute la fonction avec la valeur this
set arguments
.
prototype
? n'est pas slice
une Array
méthode native ?
Array
s'agit d'une fonction constructeur et que la "classe" correspondante est Array.prototype
. Vous pouvez également utiliser[].slice
slice
est une méthode de chaque Array
instance, mais pas la Array
fonction constructeur. Vous utilisez prototype
pour accéder aux méthodes des instances théoriques d'un constructeur.
Tout d'abord, vous devriez lire comment fonctionne l'invocation de fonctions en JavaScript . Je soupçonne que cela suffit à lui seul pour répondre à votre question. Mais voici un résumé de ce qui se passe:
Array.prototype.slice
extrait la méthode de de » prototype . Mais l'appeler directement ne fonctionnera pas, car c'est une méthode (pas une fonction) et nécessite donc un contexte (un objet appelant ), sinon il lancerait .slice
Array
this
Uncaught TypeError: Array.prototype.slice called on null or undefined
La call()
méthode vous permet de spécifier le contexte d'une méthode, ce qui rend essentiellement ces deux appels équivalents:
someObject.slice(1, 2);
slice.call(someObject, 1, 2);
Sauf que le premier nécessite que la slice
méthode existe dans someObject
la chaîne de prototypes de (comme il le fait pour Array
), tandis que le second permet au contexte ( someObject
) d'être passé manuellement à la méthode.
En outre, ce dernier est l'abréviation de:
var slice = Array.prototype.slice;
slice.call(someObject, 1, 2);
C'est la même chose que:
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 (arguments) est la méthode à l'ancienne pour convertir un argument en tableau.
Dans ECMAScript 2015, vous pouvez utiliser Array.from ou l'opérateur de propagation:
let args = Array.from(arguments);
let args = [...arguments];
C'est parce que, comme le note MDN
L'objet arguments n'est pas un tableau. Il est similaire à un tableau, mais n'a aucune propriété de tableau à l'exception de la longueur. Par exemple, il n'a pas la méthode pop. Cependant, il peut être converti en un véritable tableau:
Ici, nous faisons appel slice
à l'objet natif Array
et non à sa mise en œuvre et c'est pourquoi le supplément.prototype
var args = Array.prototype.slice.call(arguments);
N'oubliez pas, qu'une base basique de ce comportement est la fonte de type qui s'est entièrement intégrée au moteur JS.
Slice prend simplement l'objet (grâce à la propriété arguments.length existante) et retourne le tableau-objet casté après avoir fait toutes les opérations dessus.
Les mêmes logiques que vous pouvez tester si vous essayez de traiter la méthode String avec une valeur INT:
String.prototype.bold.call(11); // returns "<b>11</b>"
Et cela explique la déclaration ci-dessus.
Il utilise les slice
tableaux méthode ont et appelle son this
être l' arguments
objet. Cela signifie qu'il l'appelle comme si vous supposiez arguments.slice()
qu'il arguments
avait une telle méthode.
La création d'une tranche sans argument prendra simplement tous les éléments - elle copie donc simplement les éléments de arguments
dans un tableau.
Supposons que vous ayez: function.apply(thisArg, argArray )
La méthode apply appelle une fonction, en passant l'objet qui sera lié à cela et un tableau optionnel d'arguments.
La méthode slice () sélectionne une partie d'un tableau et renvoie le nouveau tableau.
Ainsi, lorsque vous appelez Array.prototype.slice.apply(arguments, [0])
la méthode de tranche de tableau est invoquée (bind) sur les arguments.
Peut-être un peu tard, mais la réponse à tout ce gâchis est que call () est utilisé dans JS pour l'héritage. Si nous comparons cela à Python ou PHP, par exemple, call est utilisé respectivement comme super (). init () ou parent :: _ construct ().
Ceci est un exemple de son utilisation qui clarifie tout:
function Teacher(first, last, age, gender, interests, subject) {
Person.call(this, first, last, age, gender, interests);
this.subject = subject;
}
Référence: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Inheritance
lorsque .slice () est appelé normalement, il s'agit d'un tableau, puis il itère simplement sur ce tableau et fait son travail.
//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"]
J'écris juste ceci pour me rappeler ...
Array.prototype.slice.call(arguments);
== Array.prototype.slice(arguments[1], arguments[2], arguments[3], ...)
== [ arguments[1], arguments[2], arguments[3], ... ]
Ou utilisez simplement cette fonction pratique $ A pour transformer la plupart des choses en un tableau.
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);
}
exemple d'utilisation ...
function test() {
$A( arguments ).forEach( function(arg) {
console.log("Argument: " + arg);
});
}