В области видимости любой функции в JavaScript есть доступ к специальной переменной arguments. Эта переменная содержит в себе список всех аргументов, переданных данной функции.
Замечание: В случае, если переменная
argumentsуже была объявлена в области видимости функции либо путём присвоения через выражениеvar, либо являясь формальным параметром, объектargumentsне будет создан.
Объект arguments не является наследником Array. Он, конечно же, очень похож на массив, и даже содержит свойство length — но он не наследует Array.prototype, а представляет собой Object.
По этой причине, у объекта arguments отсутствуют стандартные методы массивов, такие как push, pop или slice. Хотя итерация с использованием обычного цикла for по агрументам работает вполне корректно, вам придётся конвертировать этот объект в настоящий массив типа Array, чтобы применять к нему стандартные методы массивов.
Указанный код вернёт новый массив типа Array, содержащий все элементы объекта arguments.
Array.prototype.slice.call(arguments);
Эта конвертация занимает много времени и использовать её в критических частях кода не рекомендуется.
Ниже представлен рекомендуемый способ передачи аргументов из одной функции в другую.
function foo() {
bar.apply(null, arguments);
}
function bar(a, b, c) {
// делаем здесь что-нибудь
}
Другой трюк — использовать и call и apply вместе, чтобы быстро создать несвязанную обёртку:
function Foo() {}
Foo.prototype.method = function(a, b, c) {
console.log(this, a, b, c);
};
// Создаём несвязанную версию "method"
// Она принимает параметры: this, arg1, arg2...argN
Foo.method = function() {
// Результат: Foo.prototype.method.call(this, arg1, arg2... argN)
Function.call.apply(Foo.prototype.method, arguments);
};
Объект arguments создаёт по геттеру и сеттеру и для всех своих свойств и для формальных параметров функции.
В результате, изменение формального параметра также изменит значение соответствующего свойства объекта arguments и наоборот.
function foo(a, b, c) {
arguments[0] = 2;
a; // 2
b = 4;
arguments[1]; // 4
var d = c;
d = 9;
c; // 3
}
foo(1, 2, 3);
Объект arguments создаётся во всех случаях, лишь за двумя исключениями — когда он переопределён внутри функции (по имени) или когда одним из её параметров является переменная с таким именем. Неважно, используется при этом сам объект или нет.
Геттеры и сеттеры создаются всегда; так что, их использование практически никак не влияет на производительность.
ES5 Замечание: Эти геттеры и сеттеры не создаются в strict-режиме.
Однако, есть один момент, который может радикально понизить производительность современных движков JavaScript. Этот момент — использование arguments.callee.
function foo() {
arguments.callee; // сделать что-либо с этим объектом функции
arguments.callee.caller; // и с вызвавшим его объектом функции
}
function bigLoop() {
for(var i = 0; i < 100000; i++) {
foo(); // При обычных условиях должна бы была быть развёрнута...
}
}
В коде выше, функция foo не может быть развёрнута (а могла бы), потому что для корректной работы ей необходима ссылка и на себя и на вызвавший её объект. Это не только кладёт на лопатки механизм развёртывания, но и нарушает принцип инкапсуляции, поскольку функция становится зависима от конкретного контекста вызова.
Крайне не рекомендуется использовать arguments.callee или какое-либо из его свойств. Никогда.
ES5 Замечание: В strict-режиме использование
arguments.calleeпородитTypeError, поскольку его использование принято устаревшим.