Dlaczego używanie funkcji eval JavaScript jest złym pomysłem?

534

Funkcja eval jest potężnym i łatwym sposobem na dynamiczne generowanie kodu, więc jakie są zastrzeżenia?

Brian Singh
źródło
92
Don't be eval () autor: Simon Willison - 24ways.org/2005/dont-be-eval
Brian Singh
5
Jak opisano w moduscreate.com/javascript-performance-tips-tricks - (nowa funkcja (str)) () jest bardziej wydajna niż eval (str). Tylko moje 2 centy :)
Grgur
3
najwyraźniej nowa fcuntion (a) jest o 67% wolniejsza niż eval (a) na chromie
co to jest spać
dla mnie nowe funkcje (a) są o 80% wolniejsze najnowsze Chrome na OSX
John Smith
3
Dodałem funkcję statyczną, aby porównać wydajność. jsperf.com/eval-vs-new-function/2
Nepoxx

Odpowiedzi:

386
  1. Niewłaściwe użycie eval otwiera kod do ataków z zastrzykiem

  2. Debugowanie może być trudniejsze (brak numerów linii itp.)

  3. kod eval'd działa wolniej (brak możliwości kompilacji / buforowania kodu eval'd)

Edycja: Jak zauważył @Jeff Walden w komentarzach, # 3 jest dziś mniej prawdziwe niż w 2008 roku. Jednakże, chociaż może się zdarzyć buforowanie skompilowanych skryptów, będzie to ograniczone tylko do skryptów, które są powtarzane bez modyfikacji. Bardziej prawdopodobnym scenariuszem jest ewaluacja skryptów, które za każdym razem ulegały niewielkiej modyfikacji i jako takie nie mogły być buforowane. Powiedzmy, że NIEKTÓRY sprawdzony kod działa wolniej.

Prestaul
źródło
2
@JeffWalden, świetny komentarz. Zaktualizowałem swój post, chociaż zdaję sobie sprawę, że minął już rok od opublikowania. Xnzo72, jeśli nieco zakwalifikowałeś swój komentarz (tak jak Jeff), być może będę mógł się z tobą zgodzić. Jeff wskazał na klucz: „wielokrotna ewaluacja tego samego ciągu może uniknąć parsowania”. W tej chwili jesteś w błędzie; # 3 odnosi się do wielu scenariuszy.
Prestaul
7
@Prestaul: Skoro rzekomy atakujący może po prostu użyć dowolnego narzędzia programistycznego, aby zmienić JavaScript w kliencie, dlaczego mówisz, że Eval () otwiera twój kod na ataki z zastrzyków? Nie jest już otwarty? (Mówię oczywiście o kliencie JavaScript)
Eduardo Molteni
60
@EduardoMolteni, nie obchodzi nas (a nawet nie możemy uniemożliwić) użytkownikom wykonywania js we własnych przeglądarkach. Ataki, których próbujemy uniknąć, polegają na zapisaniu wartości podanych przez użytkownika, a następnie umieszczeniu ich w javascript i ewaluacji. Na przykład mogę ustawić moją nazwę użytkownika na: badHackerGuy'); doMaliciousThings();a jeśli weźmiesz moją nazwę użytkownika, przekształcisz ją w jakiś skrypt i sprawdzę w przeglądarkach innych osób, będę mógł uruchomić dowolny skrypt javascript na swoich komputerach (np. Zmusić ich do +1 moich postów, opublikować swoje dane na moim serwerze itp.)
Prestaul
3
Ogólnie rzecz biorąc, # 1 jest prawdą w przypadku dość wielu, jeśli nie większości wywołań funkcji. eval () nie powinien być wyróżniany i omijany przez doświadczonych programistów, tylko dlatego, że niedoświadczeni programiści nadużywają go. Jednak doświadczeni programiści często mają lepszą architekturę w swoim kodzie, a eval () rzadko będzie wymagana, a nawet zastanawiana z powodu tej lepszej architektury.
frodeborli
4
@TamilVendhan Na pewno możesz umieścić punkty przerwania. Możesz uzyskać dostęp do pliku wirtualnego utworzonego przez Chrome dla twojego zakodowanego kodu, dodając debugger;instrukcję do kodu źródłowego. Spowoduje to zatrzymanie wykonywania programu na tej linii. Następnie możesz dodać punkty przerwania debugowania, jakby to był tylko kolejny plik JS.
Sid
346

eval nie zawsze jest zły. Są chwile, kiedy jest to całkowicie właściwe.

Jednak eval jest obecnie i historycznie nadmiernie wykorzystywany przez ludzi, którzy nie wiedzą, co robią. Obejmuje to niestety osoby piszące samouczki JavaScript, aw niektórych przypadkach może to mieć konsekwencje dla bezpieczeństwa - lub częściej proste błędy. Im więcej możemy zrobić, aby przerzucić znak zapytania nad eval, tym lepiej. Za każdym razem, gdy używasz eval, musisz sprawdzać rozsądek, co robisz, ponieważ są szanse, że możesz to zrobić w lepszy, bezpieczniejszy i czystszy sposób.

Aby podać zbyt typowy przykład, aby ustawić kolor elementu o identyfikatorze przechowywanym w zmiennej „potato”:

eval('document.' + potato + '.style.color = "red"');

Gdyby autorzy powyższego kodu mieli pojęcie o podstawach działania obiektów JavaScript, zdaliby sobie sprawę, że zamiast literalnych nazw kropek można użyć nawiasów kwadratowych, co eliminuje potrzebę ewaluacji:

document[potato].style.color = 'red';

... który jest znacznie łatwiejszy do odczytania, a także mniej potencjalnie błędny.

(Ale wtedy ktoś, kto / naprawdę / wiedział, co robią, powiedziałby:

document.getElementById(potato).style.color = 'red';

który jest bardziej niezawodny niż stara sztuczka polegająca na uzyskiwaniu dostępu do elementów DOM bezpośrednio z obiektu dokumentu).

Bobin
źródło
82
Hmm, chyba miałem szczęście, kiedy uczyłem się JavaScript. Zawsze korzystałem z „document.getElementById”, aby uzyskać dostęp do DOM; jak na ironię, zrobiłem to tylko wtedy, ponieważ nie miałem pojęcia, jak działają obiekty w JavaScript ;-)
Mike Spross
5
Zgodzić się. Czasami eval jest w porządku, np. W przypadku odpowiedzi JSON z
serwisów internetowych
40
@schoetbi: Nie powinieneś używać JSON.parse()zamiast eval()JSON?
nyuszika7h,
4
@bobince code.google.com/p/json-sans-eval działa we wszystkich przeglądarkach, podobnie jak github.com/douglascrockford/JSON-js . Json2.js Douga Crockforda używa eval wewnętrznie, ale z czekami. Poza tym jest kompatybilny z wbudowaną obsługą JSON w przeglądarce.
Martijn
8
@ bobince Istnieje coś takiego jak wykrywanie funkcji i wypełnianie wielopunktowe do obsługi brakujących bibliotek JSON i innych rzeczy (patrz modernizr.com )
MauganRa
37

Uważam, że dzieje się tak dlatego, że może on wykonać dowolną funkcję JavaScript z ciągu znaków. Korzystanie z niego ułatwia ludziom wstrzykiwanie fałszywego kodu do aplikacji.

kemiller2002
źródło
5
Jaka jest zatem alternatywa?
współcześni
5
Naprawdę alternatywą jest po prostu napisanie kodu, który go nie wymaga. Crockford zastanawia się nad tym, a jeśli musisz go użyć, to prawie mówi, że jest to błąd w projektowaniu programu i należy go przerobić. W rzeczywistości też się z nim zgadzam. JS mimo wszystkich swoich wad jest naprawdę elastyczny i daje dużo miejsca na jego elastyczność.
kemiller2002
3
Nieprawda, większość frameworków ma metodę parsowania JSON, a jeśli nie używasz frameworka, możesz użyć JSON.parse (). Większość przeglądarek to obsługuje, a jeśli naprawdę masz problemy, możesz łatwo napisać parser dla JSON.
kemiller2002
6
Nie kupuję tego argumentu, ponieważ łatwo jest wstrzyknąć nieuczciwy kod do aplikacji JavaScript. Mamy konsole przeglądarki, rozszerzenia skryptów itp. Każdy pojedynczy kod wysyłany do klienta jest opcjonalny do wykonania przez klienta.
user2867288
6
Chodzi o to, że łatwiej mi wstrzykiwać kod do przeglądarki. Załóżmy, że używasz eval w ciągu zapytania. Jeśli nakłonię cię do kliknięcia linku prowadzącego do tej witryny z dołączonym ciągiem zapytania, wykonałem teraz mój kod na komputerze z pełnym zezwoleniem przeglądarki. Chcę wpisać klucz do dziennika wszystko, co piszesz na tej stronie i wysłać go do mnie? Zrobione i nie ma sposobu, aby mnie zatrzymać, ponieważ gdy eval wykonuje, przeglądarka daje mu najwyższy autorytet.
kemiller2002
27

Przychodzą mi na myśl dwa punkty:

  1. Bezpieczeństwo (ale dopóki sam generujesz ciąg do oceny, może to nie być problemem)

  2. Wydajność: dopóki kod do wykonania nie będzie znany, nie można go zoptymalizować. (o javascript i wydajności, z pewnością prezentacja Steve'a Yegge )

xtofl
źródło
9
Dlaczego bezpieczeństwo jest problemem, jeśli klient i tak może zrobić z naszym kodem wszystko, czego chce? Greasemonkey?
Paul Brewczynski
2
@PaulBrewczynski, problem bezpieczeństwa pojawia się, gdy użytkownik A zapisuje swoją część kodu, aby go wykorzystać, evala następnie ten mały fragment kodu działa w przeglądarce użytkownika B
Felipe Pereira
21

Przekazywanie danych wejściowych użytkownika do eval () stanowi zagrożenie bezpieczeństwa, ale każde wywołanie eval () tworzy nową instancję interpretera JavaScript. Może to być świnia zasobów.

Andrew Hedges
źródło
27
W ciągu ponad 3 lat, odkąd odpowiedziałem na to pytanie, moje zrozumienie tego, co się dzieje, pogłębiło się, powiedzmy,. W rzeczywistości powstaje nowy kontekst wykonania. Zobacz dmitrysoshnikov.com/ecmascript/chapter-1-execution-contexts
Andrew Hedges
20

Zasadniczo jest to problem tylko wtedy, gdy przekazujesz eval dane wejściowe od użytkownika.

Mark Biek
źródło
16

Głównie trudniej jest utrzymać i debugować. To jest jak goto. Możesz z niego korzystać, ale trudniej jest znaleźć problemy i trudniej ludziom, którzy mogą później wprowadzić zmiany.

Brian
źródło
Ewaluacji można użyć do zastąpienia brakujących funkcji metaprogramowania, takich jak szablony. Lubię kompaktowy generator o wiele bardziej niż nieskończoną listę funkcji na funkcje.
słabypust
Tak długo, jak ciąg nie pochodzi od użytkownika lub jest ograniczony do przeglądarki, którą możesz. JavaScript ma wiele możliwości metaprogramowania przy użyciu takich rzeczy, jak zmiana prototypów, obj [członek], proxy, json.parse, okno, funkcje dekoratora (przysłówki), gdzie newf = decorator (oldf), funkcje wyższego rzędu, takie jak Array.prototype.map (f) , przekazywanie argumentów do innych funkcji, argumenty słów kluczowych za pośrednictwem {}. Czy możesz podać mi przypadek użycia, w którym nie można tego zrobić zamiast ewaluacji?
aoeu256
13

Należy pamiętać, że często można użyć eval () do wykonania kodu w innym ograniczonym środowisku - witryny sieci społecznościowych, które blokują określone funkcje JavaScript, mogą czasem zostać oszukane przez rozbicie ich na blok eval -

eval('al' + 'er' + 't(\'' + 'hi there!' + '\')');

Więc jeśli chcesz uruchomić kod JavaScript, który w innym przypadku może nie być dozwolony ( Myspace , patrzę na ciebie ...), eval () może być użyteczną sztuczką.

Jednak z wszystkich wyżej wymienionych powodów nie powinieneś używać go do własnego kodu, w którym masz pełną kontrolę - to po prostu nie jest konieczne, a lepiej umieścić na półce „trudnych hackerów JavaScript”.

matowy Lohkamp
źródło
1
Po prostu aktualizuję powyższy kod ... - tam! - musi być w cudzysłowie, ponieważ jest to ciąg znaków. eval ('al' + 'er' + 't (' + '„hi there!” ”+ +)));
Mahesh
2
[]["con"+"struc"+"tor"]["con"+"struc"+"tor"]('al' + 'er' + 't(\'' + 'hi there!' + '\')')()
Konrad Borowski,
3
Tak, były serwisy społecznościowe, które ograniczały alert (), ale pozwalały na eval () ?!
joshden
12

O ile nie pozwalasz eval () na dynamiczną treść (przez cgi lub wprowadzanie danych), jest ona tak bezpieczna i solidna jak wszystkie inne JavaScript na twojej stronie.

Thevs
źródło
Chociaż jest to prawda - jeśli Twoje treści nie są dynamiczne, jaki jest powód, aby w ogóle używać eval? Zamiast tego możesz po prostu wstawić kod do funkcji i wywołać go!
Periata Breatta
Na przykład - aby przeanalizować zwracaną wartość (jak JSON, ciągi zdefiniowane przez serwer itp.), Która pochodzi z wywołania Ajax.
Thevs
2
Rozumiem. Nazwałbym je dynamicznymi, ponieważ klient nie wie z góry, czym są, ale rozumiem, co masz na myśli.
Periata Breatta
7

Wraz z resztą odpowiedzi nie sądzę, aby stwierdzenia eval mogły mieć zaawansowaną minimalizację.

Paul Mendoza
źródło
6

Jest to możliwe zagrożenie bezpieczeństwa, ma inny zakres wykonywania i jest dość nieefektywne, ponieważ tworzy całkowicie nowe środowisko skryptowe do wykonywania kodu. Zobacz tutaj, aby uzyskać więcej informacji: eval .

Jest to jednak dość przydatne i używane z umiarem może dodać wiele dobrej funkcjonalności.

Tomek
źródło
5

O ile nie masz 100% pewności, że oceniany kod pochodzi z zaufanego źródła (zwykle z własnej aplikacji), to niezawodny sposób na narażenie twojego systemu na atak skryptu między witrynami.

John Topley
źródło
1
Tylko jeśli twoje zabezpieczenia po stronie serwera są do bani. Bezpieczeństwo po stronie klienta to po prostu bzdura.
doubleOrt,
5

Wiem, że ta dyskusja jest stara, ale bardzo podoba mi się to podejście Google i chciałem podzielić się tym z innymi;)

Drugą rzeczą jest to, że im lepiej, tym więcej próbujesz zrozumieć, a na koniec po prostu nie wierzysz, że coś jest dobre lub złe tylko dlatego, że ktoś tak powiedział :) To bardzo inspirujące wideo, które pomogło mi więcej myśleć :) DOBRE PRAKTYKI są dobre, ale nie używaj ich bezmyślnie :)

op1ekun
źródło
1
Tak. Znalazłem, jak dotąd, w Chrome, przypadek użycia, który wydaje się być bardziej wydajny. Uruchom RAF, który ewaluuje ciąg w danej zmiennej podczas każdej iteracji. Użyj setInterval, aby ustawić w tym ciągu tylko elementy graficzne, takie jak ustawianie transformacji itp. Próbowałem wielu innych podejść, takich jak zapętlanie funkcji w tablicy lub używanie zmiennej do ustawiania transformacji tylko dla elementów, które zostały zmienione, ale jak dotąd wydaje się to najbardziej wydajne. Jeśli chodzi o animację, najprawdziwszym testem laboratoryjnym są twoje oczy.
jdmayfield
5

Niekoniecznie tak źle, pod warunkiem, że wiesz, w jakim kontekście go używasz.

Jeśli twoja aplikacja używa eval()do utworzenia obiektu z jakiegoś JSON, który wrócił z XMLHttpRequest do twojej własnej strony, utworzonej przez zaufany kod po stronie serwera, prawdopodobnie nie jest to problem.

Niezaufany kod JavaScript po stronie klienta i tak nie może wiele zdziałać. Pod warunkiem, że to, co wykonujesz eval(), pochodzi z rozsądnego źródła, nic ci nie jest.

MarkR
źródło
3
Czy używanie eval nie jest wolniejsze niż tylko analizowanie JSON?
Brendan Long,
@Qix - uruchomienie tego testu w mojej przeglądarce (Chrome 53) pokazuje eval jako nieco szybszy niż parsowanie .
Periata Breatta
@PeriataBreatta Huh, dziwne. Zastanawiam się dlaczego. Wtedy skomentowałem, że tak nie jest. Jednak nie jest rzadkością, że Chrome uzyskuje dziwne zwiększenie wydajności w niektórych obszarach środowiska wykonawczego od wersji do wersji.
Qix - MONICA MISTREATED 26.10.16
Trochę starego wątku tutaj, ale z tego, co przeczytałem - nie twierdząc, że sam to prześledziłem - JSON.parse w rzeczywistości eval jest wkładem w końcowy etap. Pod względem wydajności wymaga więcej pracy / czasu. Ale jeśli chodzi o bezpieczeństwo, dlaczego nie przeanalizować? eval to niesamowite narzędzie. Użyj go do rzeczy, które nie mają innej drogi. Aby przekazać funkcje przez JSON, istnieje sposób na wykonanie tego bez eval. Ten drugi parametr w JSON.stringify pozwala na wywołanie zwrotne do uruchomienia, które można sprawdzić za pomocą typeof, czy jest to funkcja. Następnie pobierz funkcję .toString (). Jest kilka dobrych artykułów na ten temat, jeśli szukasz.
jdmayfield
4

To znacznie obniża poziom pewności co do bezpieczeństwa.

David Plumpton
źródło
4

Jeśli chcesz, aby użytkownik wprowadził niektóre funkcje logiczne i ocenił AND AND, wówczas funkcja eval JavaScript jest idealna. Mogę zaakceptować dwa ciągi eval(uate) string1 === string2itd.

Ian
źródło
Możesz także użyć Function () {}, ale zachowaj ostrożność podczas korzystania z nich na serwerze, chyba że chcesz, aby użytkownicy przejęli Twój serwer hahahah.
aoeu256
3

Jeśli zauważysz użycie eval () w swoim kodzie, pamiętaj mantrę „eval () jest zły”.

Ta funkcja pobiera dowolny ciąg znaków i wykonuje go jako kod JavaScript. Gdy dany kod jest wcześniej znany (nie jest określany w czasie wykonywania), nie ma powodu, aby używać eval (). Jeśli kod jest generowany dynamicznie w czasie wykonywania, często istnieje lepszy sposób na osiągnięcie celu bez eval (). Na przykład użycie notacji w nawiasach kwadratowych w celu uzyskania dostępu do właściwości dynamicznych jest lepsze i prostsze:

// antipattern
var property = "name";
alert(eval("obj." + property));

// preferred
var property = "name";
alert(obj[property]);

Używanie eval()ma również wpływ na bezpieczeństwo, ponieważ możesz wykonywać kod (na przykład pochodzący z sieci), który został zmodyfikowany. Jest to powszechny antypattern w przypadku odpowiedzi JSON z żądania Ajax. W takich przypadkach lepiej jest użyć wbudowanych metod przeglądarki do przeanalizowania odpowiedzi JSON, aby upewnić się, że jest ona bezpieczna i poprawna. Dla przeglądarek, które nie obsługująJSON.parse() natywnie, możesz użyć biblioteki z JSON.org.

Ważne jest również, aby pamiętać, że przekazywanie ciągów do setInterval(), setTimeout()a Function()konstruktor jest w większości podobny do używania eval()i dlatego należy go unikać.

Za kulisami JavaScript wciąż musi oceniać i wykonywać ciąg przekazywany jako kod programowania:

// antipatterns
setTimeout("myFunc()", 1000);
setTimeout("myFunc(1, 2, 3)", 1000);

// preferred
setTimeout(myFunc, 1000);
setTimeout(function () {
myFunc(1, 2, 3);
}, 1000);

Korzystanie z nowego konstruktora Function () jest podobne do eval () i należy do niego podchodzić ostrożnie. Może to być potężny konstrukt, ale często jest niewłaściwie wykorzystywany. Jeśli absolutnie musisz użyćeval() , możesz zamiast tego rozważyć użycie nowej funkcji ().

Istnieje niewielka potencjalna korzyść, ponieważ kod oceniany w nowej funkcji () będzie działał w zasięgu funkcji lokalnej, więc wszelkie zmienne zdefiniowane przy pomocy var w analizowanym kodzie nie staną się globalne automatycznie.

Innym sposobem zapobiegania automatycznym globalizacjom jest zawinięcie eval()połączenia w natychmiastową funkcję.

12345678
źródło
Czy możesz zasugerować, w jaki sposób mógłbym ocenić nazwę zmiennej lokalnej dynamicznej bez funkcji eval? Funkcje ewaluacyjne (i podobne) są ostatecznością w większości języków, które je zawierają, ale czasami jest to konieczne. Czy w przypadku uzyskania nazwy zmiennej dynamicznej jakieś rozwiązanie jest bezpieczniejsze? W każdym razie sam javascript nie zapewnia prawdziwego bezpieczeństwa (po stronie serwera jest oczywiście główna obrona). Jeśli jesteś zainteresowany, oto mój przypadek użycia eval, który chciałbym zmienić: stackoverflow.com/a/48294208
Regular Joe
2

Oprócz możliwych problemów z bezpieczeństwem podczas wykonywania kodu przesłanego przez użytkownika, przez większość czasu istnieje lepszy sposób, który nie wymaga ponownej analizy kodu za każdym razem, gdy jest wykonywany. Anonimowe funkcje lub właściwości obiektu mogą zastąpić większość zastosowań eval i są znacznie bezpieczniejsze i szybsze.

Matthew Crumley
źródło
2

Może to stać się większym problemem, ponieważ nowa generacja przeglądarek wychodzi z pewnym smakiem kompilatora JavaScript. Kod wykonywany przez Eval może nie działać tak dobrze, jak reszta kodu JavaScript w tych nowszych przeglądarkach. Ktoś powinien wykonać profilowanie.

Brian
źródło
2

To jeden z dobrych artykułów mówiących o ewaluacji i tym, jak nie jest to zło: http://www.nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood/

Nie twierdzę, że powinieneś zabraknąć i zacząć używać eval () wszędzie. W rzeczywistości jest bardzo niewiele dobrych przypadków użycia eval (). Zdecydowanie istnieją obawy dotyczące przejrzystości kodu, możliwości debugowania, a na pewno wydajności, których nie należy przeoczyć. Ale nie powinieneś bać się go używać, gdy masz przypadek, w którym eval () ma sens. Spróbuj go najpierw nie używać, ale nie pozwól, aby ktokolwiek przestraszył cię, że twój kod jest bardziej kruchy lub mniej bezpieczny, gdy eval () jest właściwie używany.

Amr Elgarhy
źródło
2

eval () jest bardzo potężny i może być użyty do wykonania instrukcji JS lub oceny wyrażenia. Ale pytanie nie dotyczy użycia eval (), ale powiedzmy tylko, w jaki sposób złośliwy podmiot wpływa na ciąg znaków uruchamiany za pomocą eval (). Na koniec będziesz uruchamiać złośliwy kod. Z mocą wiąże się wielka odpowiedzialność. Więc używaj go mądrze, jeśli go używasz. Nie ma to większego związku z funkcją eval (), ale ten artykuł zawiera całkiem dobre informacje: http://blogs.popart.com/2009/07/javascript-injection-attacks/ Jeśli szukasz podstaw eval () spójrz tutaj: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval

Phi
źródło
2

Silnik JavaScript ma wiele optymalizacji wydajności, które wykonuje podczas fazy kompilacji. Niektóre z nich sprowadzają się do tego, że są w stanie statystycznie analizować kod podczas leksykacji i wstępnie ustalić, gdzie znajdują się wszystkie deklaracje zmiennych i funkcji, tak że potrzeba mniej wysiłku, aby rozpoznać identyfikatory podczas wykonywania.

Ale jeśli Engine znajdzie eval (..) w kodzie, zasadniczo musi założyć, że cała jego świadomość lokalizacji identyfikatora może być nieprawidłowa, ponieważ nie może wiedzieć w czasie leksykalizacji, jaki kod możesz przekazać eval (..) aby zmodyfikować zakres leksykalny lub zawartość obiektu, który można przekazać, aby utworzyć nowy zakres leksykalny, z którym należy się zapoznać.

Innymi słowy, w sensie pesymistycznym większość dokonanych przez niego optymalizacji jest bezcelowa, jeśli eval (..) jest obecny, więc po prostu wcale nie wykonuje optymalizacji.

To wszystko wyjaśnia.

Odniesienie :

https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20&%20closures/ch2.md#eval

https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20&%20closures/ch2.md#performance

hkasera
źródło
Żaden silnik javascript nie może znaleźć i sprawdzić w kodzie ze 100% gwarancją. Dlatego musi być na to gotowy w każdej chwili.
Jack Giffin
2

Nie zawsze jest to zły pomysł. Weźmy na przykład generowanie kodu. Niedawno napisałem bibliotekę o nazwie Hyperbars, która wypełnia lukę między domem wirtualnym a kierownicą . Robi to, analizując szablon kierownicy i konwertując go do hiperskryptu, który jest następnie używany przez virtual-dom. Indeks górny jest najpierw generowany jako ciąg, a przed zwróceniem eval()przekształca go w kod wykonywalny. eval()W tej szczególnej sytuacji znalazłem dokładne przeciwieństwo zła.

Zasadniczo od

<div>
    {{#each names}}
        <span>{{this}}</span>
    {{/each}}
</div>

Do tego

(function (state) {
    var Runtime = Hyperbars.Runtime;
    var context = state;
    return h('div', {}, [Runtime.each(context['names'], context, function (context, parent, options) {
        return [h('span', {}, [options['@index'], context])]
    })])
}.bind({}))

Wydajność eval()nie jest problemem w takiej sytuacji, ponieważ wystarczy zinterpretować wygenerowany ciąg tylko raz, a następnie wielokrotnie użyć wyjściowego pliku wykonywalnego.

Można zobaczyć, w jaki sposób generowania kodu został osiągnięty, jeśli jesteś ciekawy tutaj .

Wiksed
źródło
2

Chciałbym powiedzieć, że nie ma znaczenia, czy używasz eval()javascript, który jest uruchamiany w przeglądarkach. * (Zastrzeżenie)

Wszystkie współczesne przeglądarki mają konsolę programisty, w której można mimo to wykonać dowolny skrypt javascript, a każdy pół-inteligentny programista może spojrzeć na twoje źródło JS i umieścić dowolne jego części w konsoli programistów, aby zrobić to, co zechce.

* Tak długo, jak punkty końcowe serwera mają poprawną weryfikację i dezynfekcję wartości dostarczonych przez użytkownika, nie powinno mieć znaczenia, co zostanie przeanalizowane i sprawdzone w javascript po stronie klienta.

Jeśli jednak zapytasz, czy jest odpowiedni do użycia eval()w PHP, odpowiedź brzmi NIE , chyba że umieścisz na białej liście wartości, które mogą zostać przekazane do twojego polecenia eval.

Adam Copley
źródło
nie tylko istnieje konsola deweloperska, możesz również wpisać javascript: kod w pasku adresu URL, aby zbudować własną konsolę programistyczną na stronie, jeśli nie ma takiej usługi, jak ma to miejsce w przypadku starszych przeglądarek IE i urządzeń mobilnych.
Dmitry
1

Nie będę próbował obalić niczego, co powiedziałem do tej pory, ale zaoferuję użycie eval (), którego (o ile wiem) nie da się zrobić w żaden inny sposób. Prawdopodobnie istnieją inne sposoby na zakodowanie tego i prawdopodobnie sposoby na jego optymalizację, ale odbywa się to ręcznie i bez żadnych dzwonków i gwizdków dla jasności, aby zilustrować użycie eval, które tak naprawdę nie ma żadnych innych alternatyw. To znaczy: dynamiczne (a dokładniej) programowo tworzone nazwy obiektów (w przeciwieństwie do wartości).

//Place this in a common/global JS lib:
var NS = function(namespace){
    var namespaceParts = String(namespace).split(".");
    var namespaceToTest = "";
    for(var i = 0; i < namespaceParts.length; i++){
        if(i === 0){
            namespaceToTest = namespaceParts[i];
        }
        else{
            namespaceToTest = namespaceToTest + "." + namespaceParts[i];
        }

        if(eval('typeof ' + namespaceToTest) === "undefined"){
            eval(namespaceToTest + ' = {}');
        }
    }
    return eval(namespace);
}


//Then, use this in your class definition libs:
NS('Root.Namespace').Class = function(settings){
  //Class constructor code here
}
//some generic method:
Root.Namespace.Class.prototype.Method = function(args){
    //Code goes here
    //this.MyOtherMethod("foo"));  // => "foo"
    return true;
}


//Then, in your applications, use this to instantiate an instance of your class:
var anInstanceOfClass = new Root.Namespace.Class(settings);

EDYCJA: nawiasem mówiąc, nie sugerowałbym (ze wszystkich wspomnianych wcześniej względów bezpieczeństwa), aby oprzeć nazwy obiektów na danych wprowadzonych przez użytkownika. Nie mogę sobie wyobrazić żadnego dobrego powodu, dla którego chciałbyś to zrobić. Mimo to pomyślałem, że zwrócę uwagę, że nie byłby to dobry pomysł :)

Carnix
źródło
3
można to zrobić za pomocą namespaceToTest[namespaceParts[i]], bez potrzeby ewaluacji tutaj, więc if(typeof namespaceToTest[namespaceParts[i]] === 'undefined') { namespaceToTest[namespaceParts[i]] = {};jedyną różnicą dlaelse namespaceToTest = namespaceToTest[namespaceParts[i]];
user2144406
1

Zbieranie śmieci

Odśmiecanie pamięci przeglądarki nie ma pojęcia, czy ewaluowany kod można usunąć z pamięci, więc zachowuje go do momentu ponownego załadowania strony. Nieźle, jeśli użytkownicy będą wkrótce na Twojej stronie, ale może to stanowić problem dla aplikacji internetowych.

Oto skrypt pokazujący problem

https://jsfiddle.net/CynderRnAsh/qux1osnw/

document.getElementById("evalLeak").onclick = (e) => {
  for(let x = 0; x < 100; x++) {
    eval(x.toString());
  }
};

Coś tak prostego jak powyższy kod powoduje przechowywanie niewielkiej ilości pamięci do momentu śmierci aplikacji. Gorzej, gdy ewaluowany skrypt jest gigantyczną funkcją i jest wywoływany w interwale.

JD
źródło