Есть ли способ разрешить "неограниченные" переменные для функции в JavaScript?
Пример:
load(var1, var2, var3, var4, var5, etc...)
load(var1)
Есть ли способ разрешить "неограниченные" переменные для функции в JavaScript?
Пример:
load(var1, var2, var3, var4, var5, etc...)
load(var1)
Ответы:
Конечно, просто используйте arguments
объект.
function foo() {
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
arguments
это специальный объект типа «массив», что означает, что он имеет длину, но не имеет других функций массива. См. Developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… для получения дополнительной информации, и этот ответ: stackoverflow.com/a/13145228/1766230
length
свойство. Это включает в себя arguments
объект. Зная это, и что метод concat
возвращает копию из «массива» это называется, мы можем легко преобразовать arguments
объект в реальный массив , как это: var args = [].concat.call(arguments)
. Некоторые люди предпочитают использовать Array.prototype.concat.call
вместо этого, но мне нравится []
, они короткие и сладкие!
[...arguments].join()
В (большинстве) последних браузеров вы можете принимать переменное количество аргументов с этим синтаксисом:
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
Другой вариант - передать аргументы в объекте контекста.
function load(context)
{
// do whatever with context.name, context.address, etc
}
и использовать это так
load({name:'Ken',address:'secret',unused:true})
Это имеет то преимущество, что вы можете добавить столько именованных аргументов, сколько захотите, и функция может использовать их (или нет) по своему усмотрению.
context
аргумент с кодом и передать его, прежде чем он будет использован.
Я согласен с ответом Кена как с наиболее динамичным, и мне нравится делать еще один шаг вперед. Если это функция, которую вы вызываете несколько раз с разными аргументами - я использую дизайн Кена, но затем добавляю значения по умолчанию:
function load(context) {
var defaults = {
parameter1: defaultValue1,
parameter2: defaultValue2,
...
};
var context = extend(defaults, context);
// do stuff
}
Таким образом, если у вас много параметров, но вам не обязательно устанавливать их при каждом вызове функции, вы можете просто указать значения по умолчанию. Для метода extends вы можете использовать метод extend ( $.extend()
) jQuery , создать свой собственный или использовать следующее:
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];
}
Это объединит объект контекста со значениями по умолчанию и заполнит все неопределенные значения в вашем объекте значениями по умолчанию.
_.defaults()
Метод Underscore является очень хорошей альтернативой объединению заданных аргументов и аргументов по умолчанию.
Предпочтительно использовать синтаксис параметра rest, как указал Ramast.
function (a, b, ...args) {}
Я просто хочу добавить хорошее свойство аргумента ... args
- Это массив, а не объект, как аргументы. Это позволяет вам применять такие функции, как карта или сортировка напрямую.
- Он включает не все параметры, а только тот, который был передан от него. Например, функция (a, b, ... args) в этом случае args содержит аргумент 3 для arguments.length
Как уже упоминалось, вы можете использовать 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
}
Это примерно такой же объем кода (может быть, немного больше), но он должен составлять часть затрат времени выполнения.
(parameter1=context.parameter1)===undefined && (parameter1=defaultValue1)
или для меньшего объема кода небольшая вспомогательная функция, такая как: function def(providedValue, default) {return providedValue !== undefined ? providedValue : defaultValue;} var parameter1 = def(context.parameter1, defaultValue1)
предоставляет альтернативные шаблоны. Однако моя точка зрения остается неизменной: создание дополнительных объектов для каждого вызова функции и запуск дорогостоящих циклов для установки пары значений по умолчанию - это сумасшедшие затраты.
Хотя @roufamatic продемонстрировал использование ключевого слова arguments и @Ken показал отличный пример объекта для использования, я не чувствую истинного понимания того, что происходит в этом случае, и может запутать будущих читателей или привить плохую практику, поскольку явно не указывается функция / Метод предназначен для получения переменного количества аргументов / параметров.
function varyArg () {
return arguments[0] + arguments[1];
}
Когда другой разработчик просматривает ваш код, очень легко предположить, что эта функция не принимает параметры. Особенно, если этот разработчик не знаком с ключевым словом arguments . Из-за этого хорошей идеей будет следовать руководству по стилю и быть последовательным. Я буду использовать Google для всех примеров.
Давайте прямо заявим, что та же функция имеет переменные параметры:
function varyArg (var_args) {
return arguments[0] + arguments[1];
}
Могут быть случаи, когда объект необходим, так как это единственный одобренный и рассмотренный передовой метод карты данных. Ассоциативные массивы не одобряются и не одобряются.
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
Как уже упоминалось в начале ответа, ключевое слово 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
объект внутри функции, чтобы иметь доступ ко всем переданным аргументам.
Имейте в виду, что передача объекта с именованными свойствами, как предложил Кен, увеличивает стоимость выделения и освобождения временного объекта для каждого вызова. Передача нормальных аргументов по значению или по ссылке, как правило, будет наиболее эффективной. Хотя для многих приложений производительность не критична, но для некоторых это может быть.