Объект arguments¶
В области видимости любой функции в 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
, поскольку его использование принято устаревшим.