JavaScript переменное число аргументов для функции - PullRequest
486 голосов
/ 26 января 2010

Есть ли способ разрешить "неограниченные" переменные для функции в JavaScript?

Пример:

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

Ответы [ 11 ]

762 голосов
/ 26 января 2010

Конечно, просто используйте объект arguments.

function foo() {
  for (var i = 0; i < arguments.length; i++) {
    console.log(arguments[i]);
  }
}
127 голосов
/ 20 августа 2016

В (большинстве) последних браузеров вы можете принимать переменное количество аргументов с этим синтаксисом:

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

Вот небольшой пример:

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

Документация и другие примеры здесь: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters

109 голосов
/ 26 января 2010

Другой вариант - передать аргументы в объекте контекста.

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

и используйте его вот так

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

Это имеет то преимущество, что вы можете добавить столько именованных аргументов, сколько захотите, и функция может использовать их (или нет) по своему усмотрению.

45 голосов
/ 23 июля 2012

Я согласен с ответом Кена как наиболее динамичным, и я хотел бы сделать еще один шаг вперед. Если это функция, которую вы вызываете несколько раз с разными аргументами - я использую дизайн Кена, но затем добавляю значения по умолчанию:

function load(context) {

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

    var context = extend(defaults, context);

    // do stuff
}

Таким образом, если у вас много параметров, но вам не обязательно устанавливать их при каждом вызове функции, вы можете просто указать значения по умолчанию. Для метода extends вы можете использовать метод extends jQuery ($.extend()), создать свой собственный или использовать следующее:

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];
}

Это объединит объект контекста со значениями по умолчанию и заполнит все неопределенные значения в вашем объекте значениями по умолчанию.

18 голосов
/ 26 января 2010

Да, вот так:

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

load(1,2);
14 голосов
/ 02 декабря 2016

Предпочтительно использовать синтаксис параметра rest, как указал Ramast.

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

Я просто хочу добавить хорошее свойство аргумента ... args

  1. Это массив, а не объект, как аргументы. Это позволяет вам применять такие функции, как карта или сортировка напрямую.
  2. Он включает не все параметры, а только тот, который был передан из него. Например. функция (a, b, ... args) в этом случае args содержит аргумент 3 к аргументам. длина
13 голосов
/ 12 февраля 2016

Как уже упоминалось, вы можете использовать объект arguments для получения переменного числа параметров функции.

Если вы хотите вызвать другую функцию с такими же аргументами, используйте apply. Вы даже можете добавить или удалить аргументы, преобразовав arguments в массив. Например, эта функция вставляет текст перед входом в консоль:

log() {
    let args = Array.prototype.slice.call(arguments);
    args = ['MyObjectName', this.id_].concat(args);
    console.log.apply(console, args);
}
8 голосов
/ 08 февраля 2013

Хотя я в целом согласен с тем, что подход именованных аргументов полезен и гибок (если вы не заботитесь о порядке, в этом случае аргументы проще всего), у меня есть опасения относительно стоимости подхода mbeasley (с использованием значений по умолчанию и расширений). Это огромная сумма затрат на получение значений по умолчанию. Во-первых, значения по умолчанию определяются внутри функции, поэтому они заполняются при каждом вызове. Во-вторых, вы можете легко прочитать названные значения и установить значения по умолчанию одновременно, используя ||. Для получения этой информации не нужно создавать и объединять еще один новый объект.

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

   // do stuff
}

Это примерно столько же кода (может быть, немного больше), но оно должно составлять часть затрат времени выполнения.

6 голосов
/ 24 февраля 2017

Хотя @roufamatic действительно показывал использование ключевого слова arguments и @Ken показывал отличный пример объекта для использования, я не чувствую истинного понимания того, что происходит в этом случае, и может запутать будущих читателей или привить плохую практику, поскольку это явно не указание функции / метода предназначено для получения переменного количества аргументов / параметров.

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

Когда другой разработчик просматривает ваш код, очень легко предположить, что эта функция не принимает параметры. Особенно, если этот разработчик не знаком с ключевым словом arguments . Из-за этого хорошей идеей будет следовать руководству по стилю и быть последовательным. Я буду использовать Google для всех примеров.

Давайте прямо заявим, что та же функция имеет переменные параметры:

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

Параметр объекта VS var_args

Могут быть случаи, когда объект необходим, поскольку это единственный одобренный и рассмотренный наилучший метод карты данных. Ассоциативные массивы осуждаются и не поощряются.

SIDENOTE: Ключевое слово arguments на самом деле возвращает объект, используя числа в качестве ключа. Прототип наследования также является объектным семейством. Смотрите конец ответа для правильного использования массива в JS

В этом случае мы также можем это явно указать. Примечание: это соглашение об именах не предоставляется Google, но является примером явного объявления типа параметра. Это важно, если вы хотите создать более строгий типизированный шаблон в вашем коде.

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

Какой из них выбрать?

Это зависит от потребностей вашей функции и программы. Например, если вы просто хотите вернуть базу значений в итеративном процессе по всем переданным аргументам, то наверняка придерживайтесь ключевого слова arguments . Если вам нужно определение ваших аргументов и отображение данных, тогда метод объекта - путь. Давайте посмотрим на два примера, и тогда мы закончим!

Использование аргументов

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

Использование объекта

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

Доступ к массиву вместо объекта ("... args" Параметр rest)

Как уже упоминалось в верхней части ответа, ключевое слово arguments фактически возвращает объект. Из-за этого должен быть вызван любой метод, который вы хотите использовать для массива. Пример этого:

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

Чтобы избежать этого, используйте параметр rest:

function varyArgArr (...var_args) {
    return var_args.sort();
}
varyArgArr(5,1,3); // returns 1, 3, 5
5 голосов
/ 26 января 2010

Используйте объект arguments внутри функции, чтобы иметь доступ ко всем переданным аргументам.

...