web-dev-qa-db-fra.com

JavaScript variable nombre d'arguments à la fonction

Est-il possible d'autoriser des vars "illimités" pour une fonction en JavaScript?

Exemple:

load(var1, var2, var3, var4, var5, etc...)
load(var1)
493
Timo

Bien sûr, utilisez simplement l’objet arguments.

function foo() {
  for (var i = 0; i < arguments.length; i++) {
    console.log(arguments[i]);
  }
}
771
roufamatic

Dans la plupart des navigateurs récents, vous pouvez accepter un nombre variable d'arguments avec cette syntaxe:

function my_log(...args) {
     // args is an Array
     console.log(args);
     // You can pass this array as parameters to another function
     console.log(...args);
}

Voici un petit exemple:

function foo(x, ...args) {
  console.log(x, args, ...args, arguments);
}

foo('a', 'b', 'c', z='d')

=>

a
Array(3) [ "b", "c", "d" ]
b c d
Arguments
​    0: "a"
    ​1: "b"
    ​2: "c"
    ​3: "d"
    ​length: 4

Documentation et autres exemples ici: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters

136
Ramast

Une autre option consiste à transmettre vos arguments dans un objet de contexte.

function load(context)
{
    // do whatever with context.name, context.address, etc
}

et l'utiliser comme ça

load({name:'Ken',address:'secret',unused:true})

Cela présente l'avantage que vous pouvez ajouter autant d'arguments nommés que vous le souhaitez et que la fonction peut les utiliser (ou non) à sa guise.

109
Ken

Je suis d’accord avec la réponse de Ken comme étant la plus dynamique et j’aime aller plus loin. Si c'est une fonction que vous appelez plusieurs fois avec des arguments différents, j'utilise le design de Ken, mais j'ajoute ensuite les valeurs par défaut:

function load(context) {

    var defaults = {
        parameter1: defaultValue1,
        parameter2: defaultValue2,
        ...
    };

    var context = extend(defaults, context);

    // do stuff
}

Ainsi, si vous avez plusieurs paramètres mais que vous n'avez pas nécessairement besoin de les définir à chaque appel de la fonction, vous pouvez simplement spécifier les valeurs par défaut. Pour la méthode extend, vous pouvez utiliser la méthode extend de jQuery ($.extend()), créer la vôtre ou utiliser les éléments suivants:

function extend() {
    for (var i = 1; i < arguments.length; i++)
        for (var key in arguments[i])
            if (arguments[i].hasOwnProperty(key))
                arguments[0][key] = arguments[i][key];
    return arguments[0];
}

Cela fusionnera l'objet de contexte avec les valeurs par défaut et remplira toutes les valeurs non définies dans votre objet avec les valeurs par défaut.

45
mbeasley

Oui, juste comme ça:

function load()
{
  var var0 = arguments[0];
  var var1 = arguments[1];
}

load(1,2);
18
Canavar

Il est préférable d'utiliser la syntaxe du paramètre rest, comme l'a souligné Ramast.

function (a, b, ...args) {}

Je veux juste ajouter quelques propriétés de Nice de l'argument ... args

  1. C'est un tableau et non un objet comme des arguments. Cela vous permet d'appliquer des fonctions telles que mapper ou trier directement.
  2. Il n'inclut pas tous les paramètres mais uniquement celui qui en a été transmis. Par exemple. function (a, b, ... args) dans ce cas, args contient l'argument 3 en argument.length
14
Nicola Pedretti

Comme déjà mentionné, vous pouvez utiliser l'objet arguments pour récupérer un nombre variable de paramètres de fonction.

Si vous voulez appeler une autre fonction avec les mêmes arguments, utilisez apply. Vous pouvez même ajouter ou supprimer des arguments en convertissant arguments en un tableau. Par exemple, cette fonction insère du texte avant de se connecter à la console:

log() {
    let args = Array.prototype.slice.call(arguments);
    args = ['MyObjectName', this.id_].concat(args);
    console.log.apply(console, args);
}
13
Peter Tseng

Bien que je convienne généralement que l’approche des arguments nommés est utile et souple (à moins que l’ordre ne vous préoccupe, ordre dans lequel les arguments sont les plus faciles), je suis préoccupé par le coût de l’approche de mbeasley (utilisation des valeurs par défaut et étend). Cela représente un coût extrême à prendre pour extraire les valeurs par défaut. Premièrement, les valeurs par défaut sont définies dans la fonction, elles sont donc remplies à chaque appel. Deuxièmement, vous pouvez facilement lire les valeurs nommées et définir les valeurs par défaut en même temps en utilisant ||. Il n'est pas nécessaire de créer et de fusionner un autre nouvel objet pour obtenir ces informations.

function load(context) {
   var parameter1 = context.parameter1 || defaultValue1,
       parameter2 = context.parameter2 || defaultValue2;

   // do stuff
}

C'est à peu près la même quantité de code (peut-être un peu plus), mais cela ne devrait représenter qu'une fraction du coût d'exécution.

8
mcurland

Tandis que @roufamatic a montré l'utilisation du mot-clé arguments et que @Ken a montré un excellent exemple d'objet à utiliser, je ne pense pas avoir vraiment abordé ce qui se passait dans ce cas-ci et cela pourrait semer la confusion dans l'esprit des futurs lecteurs ou inculquer une mauvaise pratique/méthode est destiné à prendre une quantité variable d'arguments/paramètres.

function varyArg () {
    return arguments[0] + arguments[1];
}

Lorsqu'un autre développeur examine votre code, il est très facile de supposer que cette fonction ne prend pas de paramètres. Surtout si ce développeur n'est pas au courant du mot clé arguments. Pour cette raison, il est judicieux de suivre les directives de style et d’être cohérent. Je vais utiliser Google pour tous les exemples.

Disons explicitement que la même fonction a des paramètres variables:

function varyArg (var_args) {
    return arguments[0] + arguments[1];
}

Paramètre d'objet VS var_args

Il peut arriver qu'un objet soit nécessaire, car il s'agit de la seule méthode approuvée et considérée comme la meilleure pratique d'une carte de données. Les tableaux associatifs sont mal vus et découragés.

SIDENOTE: Le mot-clé arguments renvoie en réalité un objet en utilisant des nombres comme clé. L'héritage prototype est également la famille d'objets. Voir la fin de la réponse pour une utilisation correcte du tableau dans JS.

Dans ce cas, nous pouvons également le mentionner explicitement. Remarque: cette convention de dénomination n'est pas fournie par Google mais constitue un exemple de déclaration explicite de type param. Ceci est important si vous souhaitez créer un modèle plus strict dans votre code.

function varyArg (args_obj) {
    return args_obj.name+" "+args_obj.weight;
}
varyArg({name: "Brian", weight: 150});

Lequel choisir?

Cela dépend des besoins de votre fonction et de votre programme. Si, par exemple, vous cherchez simplement à renvoyer une base de valeurs sur un processus itératif pour tous les arguments passés, restez certainement avec le mot clé arguments. Si vous avez besoin de définir vos arguments et de mapper les données, la méthode objet est la solution. Regardons deux exemples et ensuite nous avons terminé!

Utilisation des arguments

function sumOfAll (var_args) {
    return arguments.reduce(function(a, b) {
        return a + b;
    }, 0);
}
sumOfAll(1,2,3); // returns 6

Utilisation d'objet

function myObjArgs(args_obj) {
    // MAKE SURE ARGUMENT IS AN OBJECT OR ELSE RETURN
    if (typeof args_obj !== "object") {
        return "Arguments passed must be in object form!";
    }

    return "Hello "+args_obj.name+" I see you're "+args_obj.age+" years old.";
}
myObjArgs({name: "Brian", age: 31}); // returns 'Hello Brian I see you're 31 years old

Accéder à un tableau à la place d'un objet ("... args", paramètre rest)

Comme mentionné en haut de la réponse, le mot clé arguments renvoie en fait un objet. Pour cette raison, toute méthode que vous souhaitez utiliser pour un tableau devra être appelée. Un exemple de ceci:

Array.prototype.map.call(arguments, function (val, idx, arr) {});

Pour éviter cela, utilisez le paramètre rest:

function varyArgArr (...var_args) {
    return var_args.sort();
}
varyArgArr(5,1,3); // returns 1, 3, 5
6
Brian Ellis

Utilisez l’objet arguments à l’intérieur de la fonction pour avoir accès à tous les arguments transmis.

5
nickytonline

Sachez que le fait de transmettre un objet avec les propriétés nommées, comme suggéré par Ken, ajoute le coût de l'allocation et de la libération de l'objet temporaire à chaque appel. Passer les arguments normaux par valeur ou par référence sera généralement le plus efficace. Pour de nombreuses applications, les performances ne sont pas critiques mais peuvent l'être pour certaines.

3
phbcanada