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

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

Пример:

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

13 ответов

Решение

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

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

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

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 load(context)
{
    // do whatever with context.name, context.address, etc
}

и использовать это так

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

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

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

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

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

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

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

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

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

Да, вот так:

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

load(1,2);

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

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

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

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

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

   // do stuff
}

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

Хотя @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

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

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

ПАРАМЕТРЫ ОТДЫХА

см. Остальные параметры MDN

Используйте массив, а затем вы можете использовать столько параметров, сколько вам нужно. Например, вычислите среднее число элементов массива:

      function fncAverage(sample) {
    var lenghtSample = sample.length;
    var elementsSum = 0;
    for (var i = 0; i < lenghtSample; i++) {
        elementsSum = Number(elementsSum) + Number(sample[i]);
    }
    average = elementsSum / lenghtSample
    return (average);
}

console.log(fncAverage([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])); // results 5.5

let mySample = [10, 20, 30, 40];
console.log(fncAverage(mySample)); // results 25

//try your own arrays of numbers
Другие вопросы по тегам