586 Stimmen

Warum ist die Verwendung der JavaScript eval-Funktion eine schlechte Idee?

Die eval-Funktion ist eine leistungsstarke und einfache Möglichkeit, dynamischen Code zu erzeugen.

2voto

hkasera Punkte 2030

Die JavaScript-Engine verfügt über eine Reihe von Leistungsoptimierungen, die sie während der Kompilierungsphase durchführt. Einige dieser Optimierungen laufen darauf hinaus, dass der Code während der Kompilierung im Wesentlichen statisch analysiert wird und im Voraus festgelegt wird, wo sich alle Variablen- und Funktionsdeklarationen befinden, so dass während der Ausführung weniger Aufwand für die Auflösung von Bezeichnern erforderlich ist.

Aber wenn die Engine ein eval(..) im Code findet, muss sie im Wesentlichen davon ausgehen, dass ihre gesamte Kenntnis der Identifikatorposition ungültig sein könnte, weil sie zur Lexing-Zeit nicht genau wissen kann, welchen Code Sie an eval(..) übergeben, um den lexikalischen Bereich zu ändern, oder den Inhalt des Objekts, das Sie an with übergeben, um einen neuen lexikalischen Bereich zu erstellen, der konsultiert werden soll.

Mit anderen Worten, im pessimistischen Sinne sind die meisten dieser Optimierungen, die er vornehmen würde, sinnlos, wenn eval(..) vorhanden ist, also führt er die Optimierungen einfach gar nicht durch.

Das erklärt alles.

Hinweis :

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

2voto

Wikened Punkte 65

Das ist nicht immer eine schlechte Idee. Nehmen wir zum Beispiel die Codegenerierung. Ich habe kürzlich eine Bibliothek namens Hyperbars die die Kluft zwischen virtual-dom y Lenker . Dazu wird eine Lenker-Vorlage geparst und in hyperscript die anschließend von virtual-dom verwendet wird. Das Hyperskript wird zunächst als String generiert und dann zurückgegeben, eval() um ihn in ausführbaren Code umzuwandeln. Ich habe gefunden eval() in dieser besonderen Situation das genaue Gegenteil des Bösen.

Grundsätzlich von

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

Zu diesem

(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({}))

Die Leistung von eval() ist in einer Situation wie dieser kein Problem, da Sie die generierte Zeichenkette nur einmal interpretieren müssen und die ausführbare Ausgabe dann viele Male wiederverwenden können.

Wenn Sie neugierig sind, können Sie sehen, wie die Codegenerierung erfolgt ist aquí .

2voto

Adam Copley Punkte 1485

Ich würde sogar so weit gehen zu sagen, dass es nicht wirklich wichtig ist, ob Sie eval() in Javascript, das in Browsern ausgeführt wird.*(Vorbehalt)

Alle modernen Browser haben eine Entwicklerkonsole, in der Sie beliebiges Javascript ausführen können, und jeder halbwegs intelligente Entwickler kann sich Ihren JS-Quellcode ansehen und beliebige Teile davon in die Entwicklerkonsole einfügen, um zu tun, was er will.

*Solange Ihr Server Endpunkte haben die richtige Validierung und Bereinigung von Benutzer geliefert Werte, sollte es keine Rolle, was wird geparst und eval'd in Ihrem Client-Seite Javascript.

Wenn Sie fragen würden, ob es geeignet ist, die eval() in PHP lautet die Antwort jedoch NO es sei denn, Sie Whitelist alle Werte, die an Ihre eval-Anweisung übergeben werden können.

2voto

J D Punkte 117

Müllabfuhr

Die Garbage Collection des Browsers hat keine Ahnung, ob der Code, der evaluiert wurde, aus dem Speicher entfernt werden kann, also wird er einfach gespeichert, bis die Seite neu geladen wird. Nicht allzu schlimm, wenn Ihre Benutzer nur kurz auf Ihrer Seite sind, aber es kann ein Problem für Webapps sein.

Hier ist ein Skript zur Veranschaulichung des Problems

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

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

Etwas so Einfaches wie der obige Code bewirkt, dass eine kleine Menge an Speicher gespeichert wird, bis die Anwendung stirbt. Dies ist noch schlimmer, wenn das ausgewertete Skript eine riesige Funktion ist und im Intervall aufgerufen wird.

0voto

Carnix Punkte 535

Ich werde nicht versuchen, irgendetwas von dem, was bisher gesagt wurde, zu widerlegen, aber ich werde diese Verwendung von eval() anbieten, die (soweit ich weiß) auf keine andere Weise durchgeführt werden kann. Es gibt wahrscheinlich andere Wege, dies zu codieren, und wahrscheinlich auch Wege, es zu optimieren, aber dies wird der Klarheit halber von Hand und ohne Schnickschnack gemacht, um eine Verwendung von eval zu illustrieren, für die es wirklich keine anderen Alternativen gibt. Das heißt: Dynamische (oder genauer gesagt) programmatisch erzeugte Objektnamen (im Gegensatz zu Werten).

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

EDIT: Übrigens würde ich nicht vorschlagen (aus all den oben genannten Sicherheitsgründen), dass Sie Ihre Objektnamen auf Benutzereingaben basieren. Ich kann mir auch keinen guten Grund vorstellen, warum Sie das tun sollten. Trotzdem wollte ich darauf hinweisen, dass es keine gute Idee wäre :)

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X