Функции, подобные этой и способные принимать произвольное число аргументов, называются функциями с переменным числом аргументов (ivariadic functions, variable arity functions или varargs functions). Этот термин возник вместе с появлением языка программирования С.
Обратите внимание, что функции с переменным числом аргументов не должны допускать возможность вызова с пустым списком аргументов. Будет вполне разумным использовать объект
arguments[]
при написании функции, ожидающей получить фиксированное число обязательных именованных аргументов, за которыми может следовать произвольное число необязательных неименованных аргументов.
Не следует забывать, что
arguments
фактически не является массивом - это объект
Arguments
. В каждом объекте
Arguments
имеются пронумерованные элементы массива и свойство
length
, но с технической точки зрения это не массив. Лучше рассматривать его как объект, имеющий некоторые пронумерованные свойства. Подробнее об объектах, подобных массивам, рассказывается в разделе 7.11.
У объекта
Arguments
есть одна очень необычная особенность. Когда у функции имеются именованные параметры, элементы массива объекта
Arguments
при выполнении в нестрогом режиме являются синонимами параметров, содержащих аргументы функции. Массив
arguments[]
и имена параметров - это два разных средства обращения к одним и тем же переменным. Изменение значения аргумента через имя аргумента меняет значение, извлекаемое через массив
arguments[]
. Изменение значения аргумента через массив
arguments[]
меняет значение, извлекаемое по имени аргумента. Например:
function f(x) {
console.log(x); // Выведет начальное значение аргумента
arguments[0] = null; // При изменении элемента массива изменяется х!
console.log(x); // Теперь выведет "null"
}
Определенно, это не совсем то поведение, которое можно было бы ожидать от настоящего массива. В этом случае
arguments[0]
и х могли бы ссылаться на одно и то же значение, но изменение одной ссылки не должно оказывать влияния на другую.
Эта особенность в поведении объекта
Arguments
была ликвидирована в строгом режиме, предусматриваемом стандартом ECMAScript 5. Кроме того, в строгом режиме имеется еще несколько отличий. В нестрогом режиме
arguments
– это всего лишь обычный JavaScript-идентификатор, а не зарезервированное слово. В строгом режиме не допускается использовать имя
arguments
в качестве имени параметра или локальной переменной функции и отсутствует возможность присваивать значения элементам
arguments.
8.3.2.1. Свойства callee и caller
Помимо элементов своего массива объект
Arguments
определяет свойства
callee
и
caller
. При попытке изменить значения этих свойств в строгом режиме ECMAScript 5 гарантированно возбуждается исключение
ТуреЕrror
. Однако в нестрогом режиме стандарт ECMAScript утверждает, что свойство
callee
ссылается на выполняемую в данный момент функцию. Свойство
caller
не является стандартным, но оно присутствует во многих реализациях и ссылается на функцию, вызвавшую текущую. Свойство
caller
можно использовать для доступа к стеку вызовов, а свойство
callee
особенно удобно использовать для рекурсивного
вызова неименованных функций:
var factorial = function(x) {
if (x <= 1) return 1; return x * arguments.callee(x-1);
};
8.3.3. Использование свойств объекта в качестве аргументов
Когда функция имеет более трех параметров, становится трудно запоминать правильный порядок их следования. Чтобы предотвратить ошибки и избавить программиста от необходимости заглядывать в документацию всякий раз, когда он намеревается вставить в программу вызов такой функции, можно предусмотреть возможность передачи аргументов в виде пар имя/значение в произвольном порядке. Чтобы реализовать такую возможность, при определении функции следует предусмотреть передачу объекта в качестве единственного аргумента. Благодаря такому стилю пользователи функции смогут передавать функции объект, в котором будут определяться необходимые пары имя/значение. В следующем фрагменте приводится пример такой функции, а также демонстрируется возможность определения значений по умолчанию для опущенных аргументов:
// Скопировать length элементов из массива from в массив to.
// Копирование начинается с элемента from_start в массиве from
// и выполняется в элементы, начиная с to_start в массиве to.
// Запомнить порядок следования аргументов такой функции довольно сложно.
function аггаусору(/* массив */ from, /* индекс */ from_start,
/* массив */ to, /* индекс */ to_start,
/* целое */ length)
{
// здесь находится реализация функции
}
// Эта версия функции чуть менее эффективная, но не требует запоминать порядок следования
// аргументов, а аргументы from_start и to_start по умолчанию принимают значение 0.
function easycopy(args) {
arraycopy(args.from,
args.from_start || 0,
// Обратите внимание, как назначаются args.to,
// значения по умолчанию
args.to_start || 0, args.length);
}
// Далее следует пример вызова функции easycopy:
var а = [1,2,3,4], b = [];
easycopy({from: a, to: b, length: 4});
8.3.4. Типы аргументов
В языке JavaScript параметры функций объявляются без указания их типов, а во время передачи значений функциям не производится никакой проверки их типов. Вы можете сделать свой программный код самодокументируемым, выбирая описательные имена для параметров функций и включая описание типов аргументов в комментарии, как это сделано в только что рассмотренном примере функции аггаусору. Для необязательных аргументов в комментарий можно добавлять слово «необязательный» («optional»). А если функция может принимать произвольное число аргументов, можно использовать многоточие: