Gibt es eine Möglichkeit, eine Funktion aus einer Zeichenfolge mit Javascript zu erstellen?

107

Beispielsweise;

var s = "function test(){
  alert(1);
}";

var fnc = aMethod(s);

Wenn dies die Zeichenfolge ist, möchte ich eine Funktion namens fnc. Und fnc();öffnet den Alarmbildschirm.

eval("alert(1);") löst mein Problem nicht.

ymutlu
quelle

Antworten:

73

Ich habe einen jsperf-Test für 4 verschiedene Möglichkeiten hinzugefügt, um eine Funktion aus einem String zu erstellen:

  • Verwenden von RegExp mit Funktionsklasse

    var func = "function (a, b) { return a + b; }".parseFunction();

  • Verwenden der Funktionsklasse mit "return"

    var func = new Function("return " + "function (a, b) { return a + b; }")();

  • Verwenden des offiziellen Funktionskonstruktors

    var func = new Function("a", "b", "return a + b;");

  • Eval verwenden

    eval("var func = function (a, b) { return a + b; };");

http://jsben.ch/D2xTG

2 Ergebnisbeispiele: Geben Sie hier die Bildbeschreibung ein Geben Sie hier die Bildbeschreibung ein

phnah
quelle
@KthProg Chill down;). Es ist nicht immer schlecht, wie in dieser Situation, der jsperf ist im Moment nicht verfügbar. Zum Glück habe ich die Ergebnis-Screenshots hinzugefügt, bevor er nicht verfügbar war, als ich den Kommentar von Bulk erhielt.
Phnah
@KthProg FYI Dies war eine vordefinierte Antwort, die vom Moderationssystem generiert wurde :) Sie wird in einer Warteschlange angezeigt und wir suchen nach vorgegebenen Problemen, von denen eines durch diesen Kommentar behoben werden soll. Es ist keine feste Regel, und Sie werden feststellen, dass der Kommentar in Form eines Vorschlags und nicht eines Befehls vorliegt.
Dan Smith
174

Eine bessere Möglichkeit, eine Funktion aus einer Zeichenfolge zu erstellen, ist die Verwendung von Function:

var fn = Function("alert('hello there')");
fn();

Dies hat den Vorteil / Nachteil, dass Variablen im aktuellen Bereich (wenn nicht global) nicht für die neu erstellte Funktion gelten.

Das Übergeben von Argumenten ist ebenfalls möglich:

var addition = Function("a", "b", "return a + b;");
alert(addition(5, 3)); // shows '8'
Lekensteyn
quelle
5
Stimmen Sie zu, dass FunctionSie den lokalen Bereich nicht verschmutzen, und dies evalmacht die Optimierung für Motoren so schwierig ... Mit dem OP-Beispiel würde ich:var fnc = Function('return '+s)();
CMS
Ich denke, dies sollte wahrscheinlich die akzeptierte Antwort sein. Es ist viel sicherer als eval ().
Bryan Rayner
Du, mein Freund, verdienst viele positive Stimmen. Dies hat den Vorteil, dass ein Funktionsobjekt erstellt wird, das Ereignissen usw. zugewiesen werden kann. Beispiel: element.onclick = Function ("alert ('test');");
Ryan Griggs
1
@ RyanGriggs In Ihrem Fall benötigen Sie die "eval" -Funktionalität nicht, daher ist sie besser geschrieben als element.onclick = function() { alert("test"); }.
Lekensteyn
1
Sie sind aus meinem Beispiel richtig. Wenn Sie jedoch beliebige Funktionen zuweisen möchten, die in Zeichenfolgen gespeichert sind, ist Ihre Methode perfekt. Das versuche ich eigentlich zu tun. Ich habe mehrere Funktionen in Zeichenfolgenvariablen gespeichert und möchte einer On-Click-Aktion eine zuweisen.
Ryan Griggs
38

Du bist ziemlich nah dran.

//Create string representation of function
var s = "function test(){  alert(1); }";

//"Register" the function
eval(s);

//Call the function
test();

Hier ist eine funktionierende Geige .

James Hill
quelle
Ich wusste, dass die Funktion deklariert wurde, konnte aber nicht raten, den Funktionsnamen aufzurufen. Vielen Dank.
Ymutlu
4
Obligatorische evalWarnung für zukünftige Suchende: evalKann Lücken für Hacker öffnen: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…. Wenn Sie jedoch die Gefahren kennen und diese vermeiden können, ist dies ein guter einfacher Weg Erstellen Sie eine Funktion aus einem String
Was ist, wenn Sie den Namen der Funktion nicht haben, da er aus einem Datenbankeintrag stammt?
Marcel Djaman
13

Ja, die Verwendung Functionist eine großartige Lösung, aber wir können noch einen Schritt weiter gehen und einen universellen Parser vorbereiten, der die Zeichenfolge analysiert und in eine echte JavaScript-Funktion konvertiert ...

if (typeof String.prototype.parseFunction != 'function') {
    String.prototype.parseFunction = function () {
        var funcReg = /function *\(([^()]*)\)[ \n\t]*{(.*)}/gmi;
        var match = funcReg.exec(this.replace(/\n/g, ' '));

        if(match) {
            return new Function(match[1].split(','), match[2]);
        }

        return null;
    };
}

Anwendungsbeispiele:

var func = 'function (a, b) { return a + b; }'.parseFunction();
alert(func(3,4));

func = 'function (a, b) { alert("Hello from function initiated from string!"); }'.parseFunction();
func();

hier ist jsfiddle

Mr. Pumpkin
quelle
Hallo, bitte unterstützen Sie die Funktion der Pfeilfunktion für diese Methode.
Sathish Kumar
1
Ich erhalte diesen Fehler in typescirpt "Die Eigenschaft 'parseFunction' ist für den Typ 'String' nicht vorhanden."
Cegone
11

Dynamische Funktionsnamen in JavaScript

Verwenden von Function

var name = "foo";
// Implement it
var func = new Function("return function " + name + "(){ alert('hi there!'); };")();
// Test it
func();
// Next is TRUE
func.name === 'foo'

Quelle: http://marcosc.com/2012/03/dynamic-function-names-in-javascript/

Verwenden von eval

var name = "foo";
// Implement it
eval("function " + name + "() { alert('Foo'); };");
// Test it
foo();
// Next is TRUE
foo.name === 'foo'

Verwenden von sjsClass

https://github.com/reduardo7/sjsClass

Beispiel

Class.extend('newClassName', {
    __constructor: function() {
        // ...
    }
});

var x = new newClassName();
// Next is TRUE
newClassName.name === 'newClassName'
Eduardo Cuomo
quelle
6

Diese Technik mag letztendlich der Eval-Methode entsprechen, aber ich wollte sie hinzufügen, da sie für einige nützlich sein könnte.

var newCode = document.createElement("script");

newCode.text = "function newFun( a, b ) { return a + b; }";

document.body.appendChild( newCode );

Dies entspricht dem Hinzufügen dieses <script> -Elements am Ende Ihres Dokuments, z. B.:

...

<script type="text/javascript">
function newFun( a, b ) { return a + b; }
</script>

</body>
</html>
David Newberry
quelle
3

Verwenden Sie das new Function()mit einem Return im Inneren und führen Sie es sofort aus.

var s = `function test(){
  alert(1);
}`;

var new_fn = new Function("return " + s)()
console.log(new_fn)
new_fn()

Fernando Carvajal
quelle
1

Ein Beispiel mit dynamischen Argumenten:

let args = {a:1, b:2}
  , fnString = 'return a + b;';

let fn = Function.apply(Function, Object.keys(args).concat(fnString));

let result = fn.apply(fn, Object.keys(args).map(key=>args[key]))
Brunettdan
quelle
Vielen Dank. Sehr interessant
Дмитрий Васильев