Comment Array.prototype.slice.call () fonctionne-t-il?

Je sais qu'il est utilisé pour faire des arguments un véritable tableau, mais je ne comprends pas ce qui se passe lors de l'utilisation de Array.prototype.slice.call(arguments)

Ce qui se passe sous le capot, c'est que lorsque .slice() est appelé normalement, this s'agit d'une matrice, et cela ne fait que l'itérer sur cette matrice et fait son travail.

Comment est- this dans la fonction .slice() une Array? Parce que quand vous faites:

 object.method(); 

… l' object devient automatiquement la valeur de this dans la method() . Donc avec:

 [1,2,3].slice() 

… la matrice [1,2,3] est définie comme la valeur de this dans .slice() .


Mais que se passerait-il si vous pouviez remplacer autre chose par this valeur? Tant que vous remplacez par une propriété 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 semblable à un tableau .

Les méthodes .apply() .call() et .apply() vous permettent de définir manuellement la valeur de this fonction dans une fonction. Donc, si nous définissons la valeur de this dans .slice() à un objet de type array , .slice() supposera simplement qu'il fonctionne avec un Array, et fera son objet.

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 Array, mais si vous pouvez le définir comme la valeur de .slice() , cela fonctionnera simplement, car il semble assez comme un Array pour .slice() pour 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 ce qui se passe alors que vous définissez un objet arguments comme étant la valeur de .slice() . Étant donné que les arguments ont une propriété .length et un tas d'indices numériques, .slice() ne fait que fonctionner comme s'il fonctionnait sur une véritable série.

L'objet arguments n'est pas en fait une instance d'un Array, et n'a aucune des méthodes Array. Donc, arguments.slice(...) ne fonctionnera pas car l'objet arguments n'a pas la méthode de tranche.

Les tableaux ont cette méthode, et parce que l'objet arguments 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 utiliser Array.prototype ? The Array est l'objet dont nous créons de nouveaux tableaux ( new Array() ), et ces nouveaux tableaux sont des méthodes et des propriétés passées, comme une tranche. Ces méthodes sont stockées dans l'objet [Class].prototype . Ainsi, pour des raisons d'efficacité, au lieu d'accéder à la méthode de tranche par (new Array()).slice.call() ou [].slice.call() , nous obtenons le tout directement à partir du prototype. C'est pourquoi nous n'avons pas besoin d'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 instance Array. La raison pour laquelle nous utilisons une tranche, cependant, est plus un «hack» que tout. La méthode de la tranche prendra un, vous l'avez deviné, une tranche d'un tableau et renvoyez cette tranche comme un nouveau tableau. Le fait de ne pas passer d'arguments (en plus de l'objet arguments comme contexte) provoque la méthode de la tranche pour prendre un morceau complet du «tableau» passé (dans ce cas, l'objet des arguments) et le renvoyer comme un nouveau tableau.

Normalement, appeler

 var b = a.slice(); 

Copiera le tableau a en b . Cependant, nous ne pouvons pas faire

 var a = arguments.slice(); 

Parce que les arguments ne sont pas un tableau réel, et n'a pas de slice comme méthode. Array.prototype.slice est la fonction de slice pour les tableaux, et l' call exécute la fonction avec this ensemble sur les 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 les notes de MDN

L'objet arguments n'est pas un tableau. Il est similaire à un tableau, mais n'a pas de propriétés de tableau sauf la longueur. Par exemple, il n'a pas la méthode pop. Cependant, il peut être converti en un véritable tableau:

Ici, nous appelons une slice sur l'objet natif Array et non sur sa mise en œuvre et c'est pourquoi .prototype

 var args = Array.prototype.slice.call(arguments); 

Tout d'abord, vous devez lire comment fonctionne l'invocation de fonction en JavaScript . Je pense que seul cela suffit pour répondre à votre question. Mais voici un résumé de ce qui se passe:

Array.prototype.slice extrait la méthode de slice partir du prototype de Array . Mais l'appelant directement ne fonctionnera pas, car il s'agit d'une méthode (pas une fonction) et nécessite donc un contexte (un objet appelant, this ), sinon il lancerait Uncaught TypeError: Array.prototype.slice called on null or undefined .

La méthode call() vous permet de spécifier le contexte d'une méthode, ce qui signifie essentiellement que ces deux appels sont équivalents:

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

Sauf que le premier requiert que la méthode de la slice existe dans la chaîne de prototypes de someObject (comme c'est le cas pour le Array ), alors que le dernier permet au contexte ( someObject ) d'être transmis manuellement à la méthode.

En outre, ce dernier est abrégé pour:

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

Quelle est la même chose que:

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

N'oubliez pas que les principes de base de bas niveau de ce comportement sont le type-casting intégré intégralement au moteur JS.

Slice prend juste l'objet (grâce à la propriété arguments.length existante) et renvoie l'objet array-frame mis en place après avoir effectué toutes les opérations à ce sujet.

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 l'énoncé ci-dessus.

Il utilise la méthode de la slice , les tableaux ont et l'appellent, c'est l'objet des arguments . Cela signifie qu'il l'appelle comme si vous aviez arguments.slice() supposant que les arguments avaient une telle méthode.

La création d'une tranche sans aucun argument prend tout simplement tous les éléments, de sorte qu'il copie simplement les éléments des arguments vers un tableau.

Supposons que vous avez: function.apply(thisArg, argArray )

La méthode d'application invoque une fonction, en passant l'objet qui sera lié à cela et un tableau d'arguments facultatif.

La méthode slice () sélectionne une partie d'un tableau et renvoie le nouveau tableau.

Donc, lorsque vous appelez Array.prototype.slice.apply(arguments, [0]) la méthode de tranche de matrice est appelée (bind) sur les arguments.

Peut-être un peu en retard, mais la réponse à tout ce désordre est que l'appel () est utilisé dans JS pour l'héritage. Si on compare cela à Python ou PHP, par exemple, l'appel est utilisé respectivement comme super (). Init () ou parent :: _ construct ().

C'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

Quand .slice () est appelé normalement, il s'agit d'un Array, et il se contente d'itérer sur cette Array, 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"] 

Array.prototype.slice.call (arguments) est l'ancienne façon de convertir un argument en un tableau.

Dans ECMAScript 2015, vous pouvez utiliser Array.from ou l'opérateur spread:

 let args = Array.from(arguments); let args = [...arguments]; 

J'écris 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); }); }