Skip to content

Latest commit

 

History

History
121 lines (86 loc) · 4.26 KB

File metadata and controls

121 lines (86 loc) · 4.26 KB

Obiekt arguments

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 arguments zostanie zadeklarowana wewnątrz funkcji poprzez var lub jako nazwa jednego z formalnych parametrów, obiekt arguments nie 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.

Konwersja do tablicy

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ść.

Przekazywanie argumentów

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);
};

Parametry formalne i indeksy argumentów

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);

Mity i prawdy o wydajności

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.callee wyrzuci TypeError ponieważ korzystanie z niej jest przestarzałe.