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

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

Пример:

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

Ответ 1

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

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

Ответ 2

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

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

Ответ 3

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

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

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

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

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

Ответ 4

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

function load(context) {

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

    var context = extend(defaults, context);

    // do stuff
}

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

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

Ответ 5

Да, вот так:

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

load(1,2);

Ответ 6

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

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

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

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

Ответ 7

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

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

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

Ответ 8

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

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

   // do stuff
}

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

Ответ 9

В то время как @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" Параметр останова)

Как уже упоминалось выше, ключевое слово 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

Ответ 10

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

Ответ 11

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