2013-05-14 13 views
8

Załóżmy, że mam następujący kod (całkowicie bezużyteczne, wiem)Czy można bezpiecznie przechodzić „argumenty” do „apply()”

function add(a, b, c, d) { 
    alert(a+b+c+d); 
} 

function proxy() { 
    add.apply(window, arguments); 
} 

proxy(1,2,3,4); 

Zasadniczo wiemy, że stosuje się spodziewa tablicę jako drugi parametr , ale wiemy też, że arguments nie jest odpowiednią tablicą. Kod działa zgodnie z oczekiwaniami, więc czy można powiedzieć, że mogę przekazać dowolny obiekt podobny do tablicy jako drugi parametr w apply()?

Następujące będzie również działać (przynajmniej w Chrome):

function proxy() { 
    add.apply(window, { 
    0: arguments[0], 
    1: arguments[1], 
    2: arguments[2], 
    3: arguments[3], 
    length: 4 
    }); 
} 

Aktualizacja: Wydaje się, że mój drugi blok kodu nie w IE < 9 natomiast pierwsza (przechodząc arguments) działa. Błąd to Array or arguments object expected, więc wyciągniemy wniosek, że zawsze bezpiecznie jest przekazać arguments, podczas gdy nie jest bezpiecznie przekazać obiekt podobny do tablicy w oldIE.

+1

Dlaczego nie powinienem być "bezpieczny"? – Neal

+0

@Neal well 'arguments' jest dość dziwną bestią, więc pewne obawy o jej użycie nie są nierozsądne. W tym przypadku nie mogę sobie wyobrazić, jak to by było problemem. – Pointy

+0

@Neal, może dlatego, że 'arguments' nie ma wielu metod, które ma zwykła tablica, a' .apply' może chcieć z nich skorzystać? – Dogbert

Odpowiedz

3

Zakładając ECMAScript 5.1: Tak. Zgodnie z ECMA-262, 10.6, obiekt arguments ma właściwości length i indeksu wymagane przez 15.3.4.3 (Function.prototype.apply).

+0

To jest najkrótsza odpowiedź, ale jest rzeczywiście bardzo punktualna w kwestii bezpieczeństwa. Czy wiesz, dlaczego mój drugi kod testowy zawodzi w ECMASCRIPT 5 IE (

+2

oh IE wyraźnie mówi: 'Obiekt Array lub arguments expected ', więc myślę, że można bezpiecznie przekazać' argumenty', nie jest bezpieczne przekazywanie obiektów tablicowych –

7

Z definicji Function.prototype.apply w MDN:

fun.apply(thisArg[, argsArray])

Można również użyć arguments parametru argsArray. arguments jest lokalną zmienną funkcji. Może być używany dla wszystkich nieokreślonych argumentów o nazwie wywoływanego obiektu. W związku z tym nie trzeba znać argumentów wywoływanego obiektu, gdy używana jest metoda apply. Możesz użyć arguments, aby przekazać wszystkie argumenty do wywoływanego obiektu. Obiekt nazwany jest następnie odpowiedzialny za obsługę argumentów.

REF:https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/apply

jako drugi argument apply przyjmuje "tablicę podobnego obiektu, określenie argumenty z których funkcja może być nazywane". Według mojej wiedzy, ten obiekt podobny do tablicy powinien mieć właściwość do wewnętrznej iteracji i zdefiniowane właściwości (zindeksowane od zera), aby uzyskać dostęp do wartości.

I to samo potwierdza mój spec: http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.4.3, jak uprzejmie wskazał @Pointy.

+2

Również [sekcja 15.3.4.3 specyfikacji] (http://www.ecma-international.org/ecma-262/5.1/#sec-15.3.4.3) wyraźnie zaznacza "apply" odnosi się tylko do wartości właściwości "length" i numerowanych (indeksowanych). – Pointy

+0

@Pointy Przypuszczam, że to * powinno * działać w ten sposób ':)' – VisioN

1

MDN może mówić tylko w implementacjach Mozilli. Rzeczywista spec do którego wszystkie implementacje powinny spełniać następujące mówi:

15.3.4.3 Function.prototype.apply (thisArg, argArray) 

When the apply method is called on an object func with arguments thisArg and 
argArray, the following steps are taken: 

1. If IsCallable(func) is false, then throw a TypeError exception. 
2. If argArray is null or undefined, then 
     Return the result of calling the [[Call]] internal method of func, 
     providing thisArg as the this value and an empty list of arguments. 
3. If Type(argArray) is not Object, then throw a TypeError exception. 
4. Let len be the result of calling the [[Get]] internal method of argArray 
     with argument "length". 
5. If len is null or undefined, then throw a TypeError exception. 
6. Let n be ToUint32(len). 
7. If n is not equal to ToNumber(len), then throw a TypeError exception. 
8. Let argList be an empty List. 
9. Let index be 0. 
10. Repeat while index < n 
     a. Let indexName be ToString(index). 
     b. Let nextArg be the result of calling the [[Get]] internal method of 
     argArray with indexName as the argument. 
     c. Append nextArg as the last element of argList. 
     d. Set index to index + 1. 
11. Return the result of calling the [[Call]] internal method of func, 
     providing thisArg as the this value and argList as the list of arguments. 

The length property of the apply method is 2. 

NOTE The thisArg value is passed without modification as the this value. This 
    is a change from Edition 3, where an undefined or null thisArg is replaced 
    with the global object and ToObject is applied to all other values and that 
    result is passed as the this value. 

Wydaje się, że w obiekcie length a indeksy numeryczne wartości są jedynymi warunkami wstępnymi.

Powiązane problemy