2015-07-01 17 views
6

rozważyć następujące kwestie:Dlaczego obiekt argumentów javascript zachowuje się tak dziwnie podczas próby modyfikacji?

foo zamierza podjąć argumenty obiekt i zmienić kolejność, przesuwając ARG1 na stanowisko arg2

function foo (args) { 
    args[2] = args[1]; 
    args[1] = undefined; 
} 

bar wywołania Foo z jego argumentów

function bar (a, b, c) { 
    foo(arguments); 
    console.log(arguments); 
} 

I spodziewać się, że wynik następujących czynności będzie podobny do: { 0: 'hello', 1: undefined, 2: 'world' }

bar('hello', 'world'); 

jednak uzyskać:

{ 
    0: 'hello', 
    1: undefined, 
    2: 'world', 
    3: undefined, 
    4: undefined, 
    5: undefined, 
    6: undefined, 
    7: undefined, 
    8: undefined, 
    9: undefined, 
    10: undefined, 
    11: undefined, 
    12: undefined, 
    13: undefined, 
    14: undefined, 
    15: undefined, 
    16: undefined, 
    17: undefined, 
    18: undefined, 
    19: undefined 
} 

Jestem w całkowitej utraty, dlaczego tak się dzieje. Ktoś ma jakieś pomysły?

biegnę to w node.js środowiska

+0

Cóż, to dziwne. Jest to prawdopodobnie związane z modyfikowaniem czegoś ('argumenty'), którego nie można modyfikować. – Cerbrus

+3

Wygląda na to, że jest to problem z V8, ponieważ przy testowaniu przeglądarki "problem" pojawia się tylko w Chrome, ale nie używa Moz Spidermonkey. TBH, uważam, że bezpośrednia manipulacja argumentami "tablica" jest niebezpieczna, a lepiej byłoby zabrać kopię z 'Array.prototype.slice.call (argumenty)' zanim zaczniesz się z tym bawić. – spender

+0

'arguments.length' jest jednak nadal tylko' 2'. – Mackan

Odpowiedz

3

arguments object nie jest tablicą. Jest to lista z wewnętrznym typem: Arguments, z właściwością length i obiektami pobierającymi/ustawiającymi dla właściwości 0 na len - 1, gdzie len jest mniejszą liczbą zadeklarowanych argumentów funkcji i liczbą elementów, które wywołały tę funkcję. Po utworzeniu tego obiektu system nie będzie się zwiększał/zmniejszał podczas działania na jego właściwościach, a próba ustawienia go nie powoduje dodawania/usuwania kluczy. Polecenia pobierające/ustawiające dla właściwości 0 do len - 1 są w rzeczywistości aliasami do nazw argumentów w ramach funkcji (tj. Po ustawieniu b = 1 zobaczysz arguments[1] === 1).

Co się stało, kiedy foo próbuje ustawić args[2] jest dodanie własności integralna wyzwala V8, aby zmienić rozmiar podstawowej przechowywanie tablicy do 20 elementów (jakoś powinien wiedzieć, że jest to rodzaj Arguments może więc zapewne ustawić go do właściwości skrótu zamiast). Jeśli ustawisz args[20] = 1 zostanie przeskalowany do 47, args[100] = 1 zmieni rozmiar do 167, ale ustawienie args[1026] = 1 uczyni to rzadki array (ale najpierw ustawienie args[1025] = 1 a następnie args[2048] nie robi to rzadki) itd

Po zmienionym, Object.keys zgłasza wszystkie 0 do 19 jako właściwości, więc console.log (który wywołuje util.format) po prostu drukuje je wszystkie.

(function (a, b, c) { (function (args) { args[2] = 1; })(arguments); console.log(Object.keys(arguments)); })("hello", "world") 

["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19"] 

To zdecydowanie błąd V8, chociaż jest bardzo ostry.