Comment puis-je convertir l'objet «arguments» en un tableau en JavaScript?

432

L' argumentsobjet en JavaScript est une verrue étrange - il agit comme un tableau dans la plupart des situations, mais ce n'est pas en fait un objet tableau. Comme il est vraiment tout autre chose , il ne possède pas les fonctions utiles à partir Array.prototypecomme forEach, sort, filteret map.

Il est très simple de construire un nouveau tableau à partir d'un objet arguments avec une simple boucle for. Par exemple, cette fonction trie ses arguments:

function sortArgs() {
    var args = [];
    for (var i = 0; i < arguments.length; i++)
        args[i] = arguments[i];
    return args.sort();
}

Cependant, c'est une chose plutôt pitoyable à faire simplement pour avoir accès aux fonctions de tableau JavaScript extrêmement utiles. Existe-t-il un moyen intégré de le faire en utilisant la bibliothèque standard?

Andrew Coleson
la source

Réponses:

724

ES6 utilisant les paramètres de repos

Si vous pouvez utiliser ES6, vous pouvez utiliser:

Paramètres de repos

function sortArgs(...args) {
  return args.sort(function (a, b) { return a - b; });
}

document.body.innerHTML = sortArgs(12, 4, 6, 8).toString();

Comme vous pouvez le lire dans le lien

La syntaxe des paramètres rest nous permet de représenter un nombre indéfini d'arguments sous forme de tableau.

Si vous êtes curieux de connaître la ...syntaxe, elle s'appelle Spread Operator et vous pouvez en lire plus ici .

ES6 utilisant Array.from ()

Utilisation de Array.from :

function sortArgs() {
  return Array.from(arguments).sort(function (a, b) { return a - b; });
}

document.body.innerHTML = sortArgs(12, 4, 6, 8).toString();

Array.from convertissez simplement les objets de type tableau ou itérables en instances de tableau.



ES5

Vous pouvez en fait simplement utiliser Arrayla slicefonction de sur un objet arguments, et il le convertira en un tableau JavaScript standard. Vous n'aurez qu'à le référencer manuellement via le prototype d'Array:

function sortArgs() {
    var args = Array.prototype.slice.call(arguments);
    return args.sort();
}

Pourquoi ça marche? Eh bien, voici un extrait de la documentation ECMAScript 5 elle - même :

REMARQUE : la slicefonction est intentionnellement générique; il ne nécessite pas que sa valeur this soit un objet Array. Par conséquent, il peut être transféré vers d'autres types d'objets pour être utilisé comme méthode. La sliceréussite de l'application de la fonction à un objet hôte dépend de l'implémentation.

Par conséquent, slicefonctionne sur tout ce qui a une lengthpropriété, ce qui est argumentspratique.


Si Array.prototype.slicec'est trop de bouchée pour vous, vous pouvez l'abréger légèrement en utilisant des littéraux de tableau:

var args = [].slice.call(arguments);

Cependant, j'ai tendance à penser que l'ancienne version est plus explicite, donc je la préférerais à la place. Abuser de la notation littérale du tableau semble hacky et semble étrange.

Jonathan Fingland
la source
5
Dans les versions récentes de Firefox (2.0?) Et ECMAScript 5, il existe une méthode Array.slice qui rend cela un peu plus simple. Vous l'appeleriez comme ceci: var arge = Array.slice (arguments, 0) ;.
Matthew Crumley
9
À quoi ça 0sert? Puisqu'il n'y a aucun argument que vous voulez passer, pourquoi ne pouvez-vous pas simplement utiliser var args = Array.prototype.slice.call(arguments);? [ La page des arguments MDC ] ( developer.mozilla.org/en/JavaScript/Reference/… ) suggère la méthode sans le 0.
Peter Ajtai
3
@Barney - le tri est nécessaire car la question d'origine veut trier les arguments. Si vous voulez simplement le convertir en tableau, ce n'est pas nécessaire.
Krease
17
"Vous ne devez pas trancher les arguments car cela empêche les optimisations dans les moteurs JavaScript (V8 par exemple)." - de MDN developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
frameworkninja
3
Je ne suis pas sûr que cela réponde à la question d'origine. Le temps a passé. Avec ES6 expérimenté dans Firefox et Chrome, le paramètre de repos devient une bonne alternative - function sortArgs(...argsToSort) { return argsToSort.sort(); }de MDN developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Kir Kanos
40

Cela vaut également la peine de référencer cette page wiki de bibliothèque de promesses Bluebird qui montre comment gérer l' argumentsobjet dans un tableau d'une manière qui rend la fonction optimisable sous le moteur JavaScript V8 :

function doesntLeakArguments() {
    var args = new Array(arguments.length);
    for(var i = 0; i < args.length; ++i) {
        args[i] = arguments[i];
    }
    return args;
}

Cette méthode est utilisée en faveur de var args = [].slice.call(arguments);. L'auteur montre également comment une étape de construction peut aider à réduire la verbosité.

jbmusso
la source
2
+1 et merci pour le lien vers la page Bluebird Optimization Killer. PS: J'ai récemment vu cette optimisation utilisée dans le projet node-thunkify .
Yves M.
29
function sortArgs(){ return [].slice.call(arguments).sort() }

// Returns the arguments object itself
function sortArgs(){ return [].sort.call(arguments) }

Certaines méthodes de tableau sont intentionnellement conçues pour ne pas exiger que l'objet cible soit un tableau réel. Ils nécessitent uniquement que la cible ait une propriété nommée longueur et indices (qui doivent être zéro ou des entiers plus grands).

[].sort.call({0:1, 1:0, length:2}) // => ({0:0, 1:1, length:2})
matyre
la source
12

Utilisation:

function sortArguments() {
  return arguments.length === 1 ? [arguments[0]] :
                 Array.apply(null, arguments).sort();
}

Array(arg1, arg2, ...) Retour [arg1, arg2, ...]

Array(str1) Retour [str1]

Array(num1)renvoie un tableau contenant des num1éléments

Vous devez vérifier le nombre d'arguments!

Array.slice version (plus lente):

function sortArguments() {
  return Array.prototype.slice.call(arguments).sort();
}

Array.push version (plus lente, plus rapide que la tranche):

function sortArguments() {
  var args = [];
  Array.prototype.push.apply(args, arguments);
  return args.sort();
}

Déplacer la version (plus lente, mais la petite taille est plus rapide):

function sortArguments() {
  var args = [];
  for (var i = 0; i < arguments.length; ++i)
    args[i] = arguments[i];
  return args.sort();
}

Array.concat version (la plus lente):

function sortArguments() {
  return Array.prototype.concat.apply([], arguments).sort();
}
LightSpeedC Kazuaki Nishizawa
la source
1
Notez qu'en raison du comportement d'aplatissement dans Array.concat, il acceptera les arguments de tableau. sortArguments (2, [3,0], 1) renvoie 0,1,2,3.
Hafthor
9

Si vous utilisez jQuery, ce qui suit est beaucoup plus facile à retenir à mon avis:

function sortArgs(){
  return $.makeArray(arguments).sort();
}
Brad
la source
1
C'est essentiellement ce que je cherchais dans JS pur, mais +1 pour l'exemple solide de la façon dont jQuery rend JS un peu plus facile à gérer.
Andrew Coleson
2
"Sauf si une autre balise pour un framework / bibliothèque est également incluse, une réponse JavaScript pure est attendue."
Michał Perłakowski
6

Dans ECMAScript 6, il n'est pas nécessaire d'utiliser de vilains hacks comme Array.prototype.slice(). Vous pouvez à la place utiliser la syntaxe étendue ( ...) .

(function() {
  console.log([...arguments]);
}(1, 2, 3))

Cela peut sembler étrange, mais c'est assez simple. Il extrait simplement argumentsles éléments et les remet dans le tableau. Si vous ne comprenez toujours pas, consultez ces exemples:

console.log([1, ...[2, 3], 4]);
console.log([...[1, 2, 3]]);
console.log([...[...[...[1]]]]);

Notez que cela ne fonctionne pas dans certains navigateurs plus anciens comme IE 11, donc si vous voulez prendre en charge ces navigateurs, vous devez utiliser Babel .

Michał Perłakowski
la source
5

Voici une référence de plusieurs méthodes de conversion d'arguments en tableau.

Quant à moi, la meilleure solution pour une petite quantité d'arguments est:

function sortArgs (){
  var q = [];
  for (var k = 0, l = arguments.length; k < l; k++){
    q[k] = arguments[k];
  }
  return q.sort();
}

Pour les autres cas:

function sortArgs (){ return Array.apply(null, arguments).sort(); }
Gheljenor
la source
+1 pour les repères. Actuellement, les graphiques montrent que votre sortArgsest 6 fois plus rapide dans Firefox, mais deux fois plus lent dans le dernier Chrome, par rapport à Array.apply.
joeytwiddle
1
Comme Array.prototype.slice est déconseillé car il empêche l'optimisation du moteur JS V8, je considère que c'est la meilleure solution jusqu'à ce qu'ES6 soit largement disponible +1
Sasha
1
De plus, les méthodes génériques de tableau comme Array.slice () sont également obsolètes
Sasha
4

Je recommande d'utiliser l' opérateur de propagation ECMAScript 6 , qui liera les paramètres de fin à un tableau. Avec cette solution, vous n'avez pas besoin de toucher l' argumentsobjet et votre code sera simplifié. L'inconvénient de cette solution est qu'elle ne fonctionne pas sur la plupart des navigateurs, vous devrez donc utiliser un compilateur JS tel que Babel. Sous le capot, Babel se transforme argumentsen un tableau avec une boucle for.

function sortArgs(...args) {
  return args.sort();
}

Si vous ne pouvez pas utiliser un ECMAScript 6, je vous recommande de regarder certaines des autres réponses telles que @Jonathan Fingland

function sortArgs() {
    var args = Array.prototype.slice.call(arguments);
    return args.sort();
}
jjbskir
la source
4

Lodash:

var args = _.toArray(arguments);

en action:

(function(){ console.log(_.toArray(arguments).splice(1)); })(1, 2, 3)

produit:

[2,3]
Zane Hooper
la source
6
Pourquoi ne pas _.toArray?
Menixator
5
Mais _.toArrayest plus approprié.
Menixator
Je dirais que _.slice est plus approprié car vous voulez souvent supprimer certains arguments principaux.
Hafthor
4

Use Array.from(), qui prend un objet de type tableau (tel que arguments) comme argument et le convertit en tableau:

(function() {
  console.log(Array.from(arguments));
}(1, 2, 3));

Notez que cela ne fonctionne pas dans certains navigateurs plus anciens comme IE 11, donc si vous voulez prendre en charge ces navigateurs, vous devez utiliser Babel .

Michał Perłakowski
la source
3
function sortArg(){
var args = Array.from(arguments); return args.sort();
}

 function sortArg(){
    var args = Array.from(arguments); 
    return args.sort();
    }
 
 console.log(sortArg('a', 'b', 1, 2, '34', 88, 20, '19', 39, 'd', 'z', 'ak', 'bu', 90));

Abk
la source
1

Une autre réponse.

Utilisez des sorts de magie noire:

function sortArguments() {
  arguments.__proto__ = Array.prototype;
  return arguments.slice().sort();
}

Firefox, Chrome, Node.js, IE11 sont OK.

LightSpeedC Kazuaki Nishizawa
la source
6
C'est certainement la meilleure solution ... si vous voulez rendre votre code complètement illisible. Aussi, __proto__est obsolète. Voir les documents MDN .
Michał Perłakowski
1

Essayez d'utiliser Object.setPrototypeOf()

Explication: Ensemble prototypede argumentsàArray.prototype

function toArray() {
  return Object.setPrototypeOf(arguments, Array.prototype)
} 

console.log(toArray("abc", 123, {def:456}, [0,[7,[14]]]))


Explication: Prenez chaque index de arguments, placez l'élément dans un tableau à l'index correspondant du tableau.

pourrait également utiliser Array.prototype.map()

function toArray() {
  return [].map.call(arguments, (_,k,a) => a[k])
} 

console.log(toArray("abc", 123, {def:456}, [0,[7,[14]]]))


Explication: Prenez chaque index de arguments, placez l'élément dans un tableau à l'index correspondant du tableau.

for..of boucle

function toArray() {
 let arr = []; for (let prop of arguments) arr.push(prop); return arr
} 

console.log(toArray("abc", 123, {def:456}, [0,[7,[14]]]))


ou Object.create()

Explication: créer un objet, définir les propriétés de l'objet sur des éléments à chaque index de arguments; ensemble prototyped'objet créé àArray.prototype

function toArray() {
  var obj = {};
  for (var prop in arguments) {
    obj[prop] = {
      value: arguments[prop],
      writable: true,
      enumerable: true,
      configurable: true
    }
  } 
  return Object.create(Array.prototype, obj);
}

console.log(toArray("abc", 123, {def: 456}, [0, [7, [14]]]))

guest271314
la source
Vous avez demandé aux gens si votre réponse répond à l'avertissement sous la question des "réponses longues". Il me semble que le principal problème avec votre réponse est que vous n'expliquez pas pourquoi on devrait utiliser l'une des méthodes que vous montrez ici. Il n'y a aucun moyen que j'utilise l'une des solutions que vous proposez car elles sont toutes pires que les solutions de la réponse acceptée. Par exemple, votre référence au doc ​​de Object.setPrototypeOfprévient qu'il s'agit d'une "opération très lente". Pourquoi diable utiliserais-je cela Array.prototype.slice.call?
Louis
@Louis Mise à jour de la réponse avec des explications pour chaque approche. La question à OP semble être "Existe-t-il un moyen intégré de le faire en utilisant la bibliothèque standard?" , pas "pourquoi on devrait utiliser l'une des méthodes" qui sont intégrées? Comment un utilisateur qui a publié une réponse peut-il déterminer avec précision si les solutions publiées sont «correctes» pour OP? Il semblerait que ce soit à l'OP de le déterminer? En fait, cette partie de la notification est ce qui a intéressé cet utilisateur: "expliquez pourquoi votre réponse est correcte" . L'une des réponses à cette question indique-t-elle: "Cette réponse est" correcte "car: x, y, z"?
guest271314
Ce que j'ai expliqué, c'est comment SO fonctionne généralement. Que le PO veuille ou non savoir pourquoi une solution est meilleure que l'autre est totalement hors de propos, car les questions posées au SO ne sont pas principalement destinées au PO mais aux centaines et milliers de personnes qui liront la question et ses réponses plus tard. De plus, les personnes qui votent sur les réponses ne sont pas tenues de voter selon ce dont le PO pourrait être satisfait.
Louis
1

Voici une solution propre et concise:

function argsToArray() {
  return Object.values(arguments);
}

// example usage
console.log(
  argsToArray(1, 2, 3, 4, 5)
  .map(arg => arg*11)
);

Object.values( )renverra les valeurs d'un objet sous forme de tableau, et puisqu'il argumentss'agit d'un objet, il se convertira essentiellement argumentsen tableau, vous fournissant ainsi toutes les fonctions d'assistance d'un tableau telles quemap , forEach, filter, etc.

Mystique
la source
0

Méthodes Benshmarck 3:

function test()
{
  console.log(arguments.length + ' Argument(s)');

  var i = 0;
  var loop = 1000000;
  var t = Date.now();
  while(i < loop)
  {
      Array.prototype.slice.call(arguments, 0); 
      i++;
  }
  console.log(Date.now() - t);


  i = 0,
  t = Date.now();
  while(i < loop)
  {
      Array.apply(null, arguments);
      i++;
  }
  console.log(Date.now() - t);

  i = 0,
  t = Date.now();
  while(i < loop)
  {
      arguments.length == 1 ? [arguments[0]] : Array.apply(null, arguments);
      i++;
  }
  console.log(Date.now() - t);
}

test();
test(42);
test(42, 44);
test(42, 44, 88, 64, 10, 64, 700, 15615156, 4654, 9);
test(42, 'truc', 44, '47', 454, 88, 64, '@ehuehe', 10, 64, 700, 15615156, 4654, 9,97,4,94,56,8,456,156,1,456,867,5,152489,74,5,48479,89,897,894,894,8989,489,489,4,489,488989,498498);

RÉSULTAT?

0 Argument(s)
256
329
332
1 Argument(s)
307
418
4
2 Argument(s)
375
364
367
10 Argument(s)
962
601
604
40 Argument(s)
3095
1264
1260

Prendre plaisir !

Matrice
la source
1
Je voudrais suggérer de modifier quelque chose comme arguments.length == 1?[arguments[0]]:Array.apply(null, arguments);pour empêcher que la fonction ne soit appelée avec un seul argument entier dummyFn(3)et provoque un résultat[,,]
nevermind
@nevermind bon travail, j'édite, ta version est meilleure;) Mais je ne comprends pas dummyFn(3)c'est quoi? cette fonction n'existe pas ...
Matrix
Euh ... tant pis, juste un exemple veut montrer comment une fonction appelée avec un seul argument entier et provoque un tableau vide de taille fixe, désolé pour mon anglais.
nevermind
0

function sortArgs(...args) {
  return args.sort(function (a, b) { return a - b; });
}

document.body.innerHTML = sortArgs(1, 2, 3, 4).toString();

wsc
la source
0

Bien que les paramètres de repos fonctionnent bien, si vous souhaitez continuer à utiliser argumentspour une raison quelconque, envisagez

function sortArgs() {
  return [...arguments].sort()
}

[...arguments]peut être considéré comme une sorte d'alternative à Array.from(arguments), qui fonctionne également parfaitement bien.

Une alternative ES7 est une compréhension de tableau:

[for (i of arguments) i].sort()

Cela peut être plus simple si vous souhaitez traiter ou filtrer les arguments avant le tri:

[for (i of arguments) if (i % 2) Math.log(i)].sort()

la source
0
 function x(){
   var rest = [...arguments]; console.log(rest);return     
   rest.constructor;
 };
 x(1,2,3)

J'ai essayé une technique de destruction simple

Gaurav
la source
0

L'objet Arguments n'est disponible qu'à l'intérieur d'un corps de fonction. Bien que vous puissiez indexer l'objet Arguments comme un tableau, il ne s'agit pas d'un tableau. Il n'a pas de propriétés de tableau autres que la longueur.

// function arguments length 5
function properties(a,b,c,d,e){
var function_name= arguments.callee.name
var arguments_length= arguments.length;
var properties_length=  properties.length; 
var function_from= properties.caller.name;
console.log('I am the function name: '+ function_name);
console.log('I am the function length, I am function spacific: '+ properties_length); 
console.log('I am the arguments length, I am context/excution spacific: '+ arguments_length);
console.log('I am being called From: '+  function_from );
}

// arguments 3
function parent(){
properties(1,2,3);
}

//arguments length 3 because execution spacific
parent();

Bien qu'il puisse être indexé comme un tableau comme vous pouvez le voir dans cet exemple:

function add(){

var sum=0;

for(var i=0; i< arguments.length;i++){

sum = sum + arguments[i];

}

return sum;

}

console.log(add(1,2,3));

Cependant, l'objet Arguments n'est pas un tableau et n'a pas d'autres propriétés que la longueur.

Vous pouvez convertir l'objet arguments en un tableau auquel point vous pouvez accéder à l'objet arguments.

Il existe de nombreuses façons d'accéder à l'objet arguments à l'intérieur d'un corps de fonction, notamment:

  1. vous pouvez appeler la méthode Array.prototoype.slice.call.

Array.prototype.slice.call (arguments)

function giveMeArgs(arg1,arg2){

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

console.log( giveMeArgs(1,2));

  1. vous pouvez utiliser le tableau littéral

[] .slice.call (arguments).

function giveMeArgs(arg1,arg2){

var args = [].slice.call(arguments);

return args;

}

console.log( giveMeArgs(1,2) );

  1. vous pouvez utiliser Rest ...

function giveMeArgs(...args){

return args;

}

console.log(giveMeArgs(1,2))

  1. vous pouvez utiliser propagation [...]

function giveMeArgs(){

var args = [...arguments];
return args;

}

console.log(giveMeArgs(1,2));

  1. vous pouvez utiliser Array.from ()

function giveMeArgs(){

var args = Array.from(arguments);

return args;

}

console.log(giveMeArgs(1,2));

Meule
la source
0

Vous pouvez créer une fonction réutilisable pour le faire avec n'importe quel argument, le plus simple est quelque chose comme ceci:

function sortArgs() {
  return [...arguments].sort();
}

sortArgs('ali', 'reza', 1, 2, 'a'); //[1, 2, "a", "ali", "reza"];

La syntaxe de propagation peut être utilisée dans ES6 et au-dessus ...

Mais si vous souhaitez utiliser quelque chose de compatible avec ES5 et les versions antérieures , vous pouvez l'utiliser Array.prototype.slice.call, donc votre code ressemble à ceci:

function sortArgs() {
  return Array.prototype.slice.call(arguments).sort();
}

sortArgs('ali', 'reza', 1, 2, 'a'); //[1, 2, "a", "ali", "reza"];

Il existe également quelques autres façons de le faire, par exemple en utilisant Array.fromou en boucle les arguments et en les affectant à un nouveau tableau ...

Alireza
la source
-2

C'est une très vieille question, mais je pense avoir une solution légèrement plus facile à taper que les solutions précédentes et qui ne s'appuie pas sur des bibliothèques externes:

function sortArguments() {
  return Array.apply(null, arguments).sort();
}
HandyAndyShortStack
la source
2
Array.applyne fonctionnera pas si vous n'avez qu'un seul argument entier positif. C'est parce que new Array(3)crée une longueur de tableau de 3. Pour être plus précis, le résultat sera [undefined, undefined, undefined]et non [3].
inf3rno