2013-07-21 18 views
6

Czy javascript pozwala na aliasing eval? Pierwsza część poniższego kodu zachowuje się nieoczekiwanie (wyświetla 1, 1), ale druga część nie (wyświetla 1, 2). Pomocne będzie odwołanie do skryptu ECMA lub dokumentów mozilla, którego nie można znaleźć.JavaScript eval alias

<html> 
<script type="application/javascript;version=1.8"> 
    (function(){ 
     eval('var testVar=1'); 
     alert(testVar); 
     var eval2=eval; 
     eval2('var testVar=2'); 
     alert(testVar); 
    })(); 

    (function(){ 
     eval('var testVar=1'); 
     alert(testVar); 
     eval('var testVar=2'); 
     alert(testVar); 
    })(); 
</script> 
</html> 
+1

W jaki sposób wynik pierwszego jest nieoczekiwany? –

+0

Gdy 'eval' nie jest aliasem, wyświetla 1, 2, patrz druga funkcja. Jeśli jest to oczekiwane, czy możesz odpowiedzieć na pytanie? Dzięki. – simonzack

+0

Tak, ale powiedziałeś, że pierwszy zachowuje się nieoczekiwanie, wyświetlając 1 i 2. To jest oczekiwane. –

Odpowiedz

7

Nie można "aliasować" eval i oczekiwać, że będzie zachowywać się tak samo. Proste. Czemu? eval nie jest funkcją.

Co się dzieje, kiedy wywołujesz eval2, ustawiasz zmienną "pamięć podręczną" do pracy ze zmiennymi globalnymi. Dlatego ustawiając w nim zmienną, ustawiasz zmienną globalną. Jednak po wyjściu zmienna "pamięć podręczna" powraca do funkcji o zakresie zasięgu. Dlatego drugi alert pokazuje 1 - zmienna globalna jest cieniowana przez funkcję poziomu pierwszego.

ta jest podana w załączniku E (strona 239) z ECMAScript (kopalnia nacisk)

10.4.2: W wersji 5, połączenia pośrednie do funkcji eval użyć globalnego środowiska zarówno jako zmienne środowisko oraz środowisko leksykalne dla kodu ewaluacyjnego. W wydaniu 3 zmienne i leksykalne środowisko osoby dzwoniącej pośredniego ewalu było używane jako środowisko dla kodu ewaluacyjnego.

Pełna definicja „Wprowadzanie kodu Eval” jest zdefiniowany w §10.5.2 (strona 58) (kopalnia nacisk)

  1. Jeśli nie ma kontekst powołanie lub jeśli kod nie jest eval oceniany przez bezpośrednie wywołanie (15.1.2.1.1) do funkcji eval następnie,
    • inicjalizację kontekstu wykonania, jak gdyby był to kontekst globalny wykonanie pomocą kodu eval jak C, jak opisano w 10.4.1.1 .
  2. Else
    • Ustaw ThisBinding na taką samą wartość jak ThisBinding kontekstu wykonania powołanie.
    • Ustawia Środowisko leksykalne na taką samą wartość, jak Środowisko leksykalne kontekstu wywołującego wykonanie .
    • Ustaw wartość VariableEnvironment na taką samą wartość, jak zmienna VariableEnvironment kontekstu wywołania wywołującego .
  3. Jeśli kod eval jest ścisły kod, a następnie
    • Let strictVarEnv być wynikiem nazywając NewDeclarativeEnvironment minięciu LexicalEnvironment jako argumentu.
    • Ustaw środowisko LexicalEnvironment na strictVarEnv.
    • Ustaw wartość VariableEnvironment na strictVarEnv.
  4. Wykonaj tworzenie zgłoszenia zgłoszenia, jak opisano w 10.5, używając kodu eval.
+1

Jeśli 'eval' nie jest funkcją, dlaczego' alert (eval) 'pokazuje' funkcję eval() {[native code]}? – Teemu

+0

Twoja pierwsza część jest niepoprawna, aliasing 'eval' działa w firefoxie i nie ma żadnych błędów, ale nie tak jak się spodziewam. Spróbuj 'eval2 (alert (" test "))'. W rzeczywistości specyfikacja ECMA mówi: "Wdrożenia nie mogą już ograniczać używania eval w sposób, który nie jest bezpośrednim połączeniem." – simonzack

+3

Źle odczytujesz standard. 'eval' * can * może być aliasowany, ale wtedy będzie działać inaczej. Zobacz pozostałe części standardu: "* Kod Eval jest tekstem źródłowym dostarczanym do ** wbudowanej funkcji eval. ***" (# 10.1), "* lub jeśli kod eval nie jest oceniany przez * * bezpośrednie połączenie *** "(nr 10.4.2) i inne. – DCoder

2

W pierwszym przypadku, gdy używasz eval, używa on zakresu funkcji, w obrębie którego jest wykonywany. Po przypisaniu eval do eval2, a następnie wykonaniu tej samej instrukcji, wydaje się, że używa kontekstu window (zasięg globalny), a nie kontekstu funkcji. Dlatego widać tę samą wartość 1 w pierwszym przypadku, ponieważ testVar wewnątrz funkcji wynosi 1, a poza window.testVar to 2. Można to udowodnić poprzez wykonanie poniżej snippet

<script> 
(function(){ 
     eval('var testVar=1'); 
     alert(window.testVar); 
     var eval2=eval; 

     eval2('var testVar=2'); 
     alert(window.testVar); 
    })(); 

    (function(){ 
     eval('var testVar=1'); 
     alert(testVar); 
     eval('var testVar=2'); 
     alert(testVar); 
    })(); 
</script> 

Faktycznie, zgodnie Mozilla Developer Network, można” t alias eval.