Переменное количество аргументов в JavaScript для функции

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

Пример:

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

person Timo    schedule 26.01.2010    source источник
comment
возможный дубликат Is можно ли отправить переменное количество аргументов функции JavaScript?   -  person Nakilon    schedule 07.02.2013
comment
связанный / возможный дубликат stackoverflow.com/questions/4633125/   -  person Luke    schedule 22.04.2015
comment
@ Люк, нет, это не так. Этот вопрос спрашивает, как вызвать функцию с произвольным количеством аргументов с аргументами в массиве. Здесь спрашивается, как справиться с таким вызовом.   -  person Scruffy    schedule 02.01.2017
comment
Для облегчения поиска такая функция называется «вариационной функцией».   -  person gschenk    schedule 23.01.2020


Ответы (11)


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

function foo() {
  for (var i = 0; i < arguments.length; i++) {
    console.log(arguments[i]);
  }
}
person roufamatic    schedule 26.01.2010
comment
Tnx. Он отлично подходит для синтаксического анализа строк из собственного кода Android в javascript в веб-просмотре. - person Johan Hoeksma; 31.08.2013
comment
Это решение сработало для меня лучше всего. Спасибо. Дополнительная информация о ключевом слове arguments ЗДЕСЬ. - person User2; 30.04.2014
comment
arguments - это особый объект, подобный массиву, что означает, что он имеет длину, но не имеет других функций массива. См. developer.mozilla.org/en-US/docs. / Web / JavaScript / Reference / для получения дополнительной информации и этот ответ: stackoverflow.com/a/13145228/1766230 - person Luke; 22.04.2015
comment
Интересно, что методы Array в Javascript были определены таким образом, что они работают с любым объектом, имеющим свойство length. Сюда входит объект arguments. Зная это и что метод concat возвращает копию «массива», который он вызвал, мы можем легко преобразовать объект arguments в реальный массив, например: var args = [].concat.call(arguments). Некоторые люди предпочитают вместо этого использовать Array.prototype.concat.call, но мне нравится [], они короткие и милые! - person Stijn de Witt; 11.11.2016
comment
Этот подход НЕ работает с стрелочными функциями. Вы можете использовать подход Рамаста (см. Ниже) - person anhldbk; 21.07.2017
comment
Устарело Эта функция была удалена из веб-стандартов. Хотя некоторые браузеры могут по-прежнему поддерживать его, в настоящее время он удаляется. Избегайте его использования и по возможности обновите существующий код; см. таблицу совместимости внизу этой страницы, чтобы принять решение. Имейте в виду, что эта функция может перестать работать в любой момент. - person David Gatti; 02.09.2017
comment
@DavidGatti Похоже, использование Function.arguments устарело, но не ванильный объект arguments. См. developer.mozilla.org/en-US/docs. / Web / JavaScript / Reference /. - person roufamatic; 06.09.2017
comment
Что вы понимаете под ванилью? Я все еще вижу большой палец рядом с ним. - person David Gatti; 06.09.2017
comment
@DavidGatti Из текста под большим пальцем вниз: Это устарело как свойство функции. Вместо этого используйте объект arguments, доступный в функции. - person roufamatic; 07.09.2017
comment
@StijndeWitt: Когда я пробую то, что вы предлагаете, я получаю одноэлементный массив, элемент которого представляет собой хеш с ключами 0, 1, ... - person Ben Crowell; 23.06.2018
comment
Похоже, вы добавляете объект arguments в массив. Обязательно используйте call для вызова функции concat. Если вы вызовете его напрямую, объект будет добавлен. Уловка с использованием call заключается в том, что concat будет вызываться с arguments, поскольку это this. Таким образом, он клонирует объект arguments в реальный массив. - person Stijn de Witt; 25.06.2018
comment
Хотел бы я сделать arguments.join (). - person Yasir Jan; 11.04.2019
comment
@YasirJan использовать [...arguments].join() - person Willian D. Andrade; 22.07.2019

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

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.

person Ramast    schedule 20.08.2016
comment
К вашему сведению, это называется синтаксисом остальных параметров: developer.mozilla .org / en-US / docs / Web / JavaScript / Reference / - person tanguy_k; 16.11.2016
comment
+1 Элегантное и чистое решение. Особенно подходит для передачи длинного списка параметров в вызов другой функции, и, возможно, эти переменные параметры находятся в произвольной позиции. - person haxpor; 06.09.2017
comment
Имейте в виду, что согласно developer.mozilla.org/ en-US / docs / Web / JavaScript / Reference / не поддерживается в IE. - person Roee Gavirel; 31.12.2018
comment
Вот таблица, показывающая поддержку браузером - caniuse.com/#feat=rest-parameters - person Brian Burns; 10.04.2019
comment
Такой хороший ответ! - person Ashish; 13.08.2019

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

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

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

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

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

person Ken    schedule 26.01.2010
comment
Это было бы лучше, поскольку это устраняет связь с порядком аргументов. Слабосвязанные интерфейсы - хорошая стандартная практика ... - person Jonas Schubert Erlandsson; 30.01.2013
comment
Конечно, в некоторых случаях так лучше. Но предположим, что отдельные аргументы на самом деле не связаны друг с другом или все должны иметь одинаковое значение (например, элементы массива). Тогда лучше всего подходит OP. - person rvighne; 09.12.2013
comment
Это также хорошо, потому что, если вы хотите, вы можете создать аргумент context с помощью кода и передать его до того, как он будет использован. - person Nate C-K; 29.01.2014

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

function load(context) {

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

    var context = extend(defaults, context);

    // do stuff
}

Таким образом, если у вас много параметров, но не обязательно устанавливать их при каждом вызове функции, вы можете просто указать значения, отличные от значений по умолчанию. Для метода расширения вы можете использовать метод расширения 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];
}

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

person mbeasley    schedule 23.07.2012
comment
+1. Хороший трюк. Сохраняет много шаблонов, чтобы каждый параметр был определен, по умолчанию или иначе. - person Neil; 17.09.2012
comment
Метод Underscore _.defaults() - очень хорошая альтернатива слиянию указанных аргументов и аргументов по умолчанию. - person mbeasley; 14.02.2013

Как указал Рамаст, предпочтительно использовать синтаксис параметров отдыха.

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

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

  1. Это массив, а не объект, подобный аргументам. Это позволяет вам напрямую применять такие функции, как карта или сортировка.
  2. Он не включает все параметры, а только тот, который передается от него. Например. function (a, b, ... args) в этом случае args содержит аргумент 3 для arguments.length
person Nicola Pedretti    schedule 02.12.2016

Да вот так:

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

load(1,2);
person Canavar    schedule 26.01.2010

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

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

log() {
    let args = Array.prototype.slice.call(arguments);
    args = ['MyObjectName', this.id_].concat(args);
    console.log.apply(console, args);
}
person Peter Tseng    schedule 12.02.2016
comment
хорошее решение для преобразования аргументов в массив. Сегодня это мне помогло. - person Dmytro Medvid; 13.02.2016

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

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

   // do stuff
}

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

person mcurland    schedule 07.02.2013
comment
Согласен, хотя вред зависит от типа значения или самого значения по умолчанию. В противном случае (parameter1=context.parameter1)===undefined && (parameter1=defaultValue1) или для меньшего объема кода небольшая вспомогательная функция, например: function def(providedValue, default) {return providedValue !== undefined ? providedValue : defaultValue;} var parameter1 = def(context.parameter1, defaultValue1), предоставит альтернативные шаблоны. Однако моя точка зрения остается неизменной: создание дополнительных объектов для каждого вызова функции и запуск дорогостоящих циклов для установки пары значений по умолчанию - это сумасшедшие накладные расходы. - person mcurland; 29.08.2014

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

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" Остальной параметр)

Как упоминалось в начале ответа, ключевое слово 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
person Brian Ellis    schedule 24.02.2017

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

person nickytonline    schedule 26.01.2010

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

person phbcanada    schedule 06.08.2014