Każdy zasięg funkcyjny w języku JavaScript ma dostęp do specjalnej zmiennej arguments.
Ta zmienna trzyma listę wszystkich argumentów przekazanych do funkcji.
Uwaga: W przypadku gdy
argumentszostanie zadeklarowana wewnątrz funkcji poprzezvarlub jako nazwa jednego z formalnych parametrów, obiektargumentsnie zostanie utworzony.
Obiekt arguments nie jest typu Array. Mimo że posiada pewne cechy
semantyki tablic - właściwość length - to w rzeczywistości nie dziedziczy
on z Array.prototype, tylko z Object.
Ze względu na to, na obiekcie arguments nie można używać standardowych dla tablic metod,
takich jak push, pop czy slice. Mimo że iteracja przy pomocy
pętli for działa dobrze, to aby skorzystać ze standardowych metod tablicowych
należy skonwertować arguments do prawdziwego obiekt Array.
Poniższy kod zwróci nowy obiekt Array zawierający wszystkie elementy
obiektu arguments.
Array.prototype.slice.call(arguments);
Jednakże konwersja ta jest wolna i nie jest zalecana w sekcjach, które mają duży wpływ na wydajność.
Zalecany sposób przekazywania argumentów z jednej funkcji do następnej wyglada następująco:
function foo() {
bar.apply(null, arguments);
}
function bar(a, b, c) {
// do stuff here
}
Kolejną sztuczką jest użycie razem call i apply w celu stworzenia
szybkich i nieograniczonych wrapperów.
function Foo() {}
Foo.prototype.method = function(a, b, c) {
console.log(this, a, b, c);
};
// Stworzenie nieograniczoną wersję metody "method"
// która przyjmuje parametry: this, arg1, arg2...argN
Foo.method = function() {
// Rezultat: Foo.prototype.method.call(this, arg1, arg2... argN)
Function.call.apply(Foo.prototype.method, arguments);
};
Obiekt arguments tworzy funkcje getter i setter nie tylko dla swoich
właściwości, ale również dla parametrów formalnych funkcji.
W rezultacie zmiana wartości parametru formalnego zmieni również wartość
odpowiadającemu mu wpisowi w obiekcie arguments. Zachodzi to również w drugą stronę.
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);
Obiekt arguments jest tworzony zawsze, z wyjątkiem dwóch przypadków, gdy
zmienna o takiej nazwie jest zdefiniowana wewnątrz funkcji lub jeden z parametrów
formalnych funkcji ma taką nazwę. Nie ma znaczenia czy obiekt arguments jest
używany czy nie.
Zarówno gettery jak i settery są zawsze tworzone, zatem używanie ich nie ma
praktycznie żadnego wpływu na wydajność. Zwłaszcza w rzeczywistym kodzie, który
wykorzystuje coś więcej niż tylko prosty dostęp do właściwości obiektu arguments.
Uwaga ES5: gettery and settery nie są tworzone w trybie strict mode
Jednakże, istnieje jeden przypadek w którym wydajność drastycznie spada w
nowoczesnych silnikach JavaScript. Ten przypadek to wykorzystanie
arguments.callee.
function foo() {
arguments.callee; // operowanie na obiekcie funkcji
arguments.callee.caller; // i obiekcie funkcji wywołującej
}
function bigLoop() {
for(var i = 0; i < 100000; i++) {
foo(); // Normalnie zostałaby wykorzystana metoda inline
}
}
W powyższym przykładzie foo nie może zostać wykorzystana metoda inline
ponieważ potrzebne są nie tylko informacje na własny temat ale również
na temat funkcji wywołującej. Takie użycie nie tylko uniemożliwia
inlining i korzyści z niego wynikające, ale też łamie zasady enkapsulacji,
ponieważ ta funkcja jest zależna od kontekstu w jakim została wywołana.
Mocno zalecane jest aby nigdy nie korzystać z arguments.callee
i żadnej jej własności.
Uwaga ES5: W trybie strict mode,
arguments.calleewyrzuciTypeErrorponieważ korzystanie z niej jest przestarzałe.