Czy istnieje sposób na utworzenie funkcji z ciągu znaków za pomocą javascript?


108

Na przykład;

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

var fnc = aMethod(s);

Jeśli to jest ciąg, chcę funkcję o nazwie fnc. I fnc();wyskakuje ekran ostrzegawczy.

eval("alert(1);") nie rozwiązuje mojego problemu.

Odpowiedzi:


73

Dodałem test jsperf dla 4 różnych sposobów tworzenia funkcji z łańcucha:

  • Używanie RegExp z klasą Function

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

  • Używanie klasy funkcji z wartością „return”

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

  • Korzystanie z oficjalnego konstruktora funkcji

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

  • Korzystanie z Eval

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

http://jsben.ch/D2xTG

2 próbki wyników: wprowadź opis obrazu tutaj wprowadź opis obrazu tutaj


@KthProg Chill down;). Nie zawsze jest źle, jak ta sytuacja, jsperf w tej chwili nie działa, na szczęście dodałem zrzuty ekranu z wynikami, zanim został wyłączony, kiedy dostałem komentarz od Bulka.
— phnah

@KthProg FYI to była gotowa odpowiedź wygenerowana przez system moderacji :) pojawia się w kolejce i sprawdzamy, czy nie ma z góry określonych problemów, z których jeden ma naprawić ten komentarz. Nie jest to sztywna i szybka reguła, a zauważysz, że komentarz ma formę sugestii, a nie polecenia.
— Dan Smith

175

Lepszym sposobem na utworzenie funkcji z łańcucha jest użycie Function:

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

Ma to tę zaletę / wadę, że zmienne w bieżącym zakresie (jeśli nie są globalne) nie mają zastosowania do nowo skonstruowanej funkcji.

Możliwe jest również przekazywanie argumentów:

var addition = Function("a", "b", "return a + b;");
alert(addition(5, 3)); // shows '8'

5
Zgadzam się, Functionnie zanieczyszczasz zakresu lokalnego i dlatego evaloptymalizacja jest tak trudna dla silników ... Na przykładzie OP:var fnc = Function('return '+s)();
— CMS

Myślę, że to prawdopodobnie powinna być akceptowana odpowiedź. Jest dużo bezpieczniejsze niż eval ().
— Bryan Rayner,

Ty, mój przyjacielu, zasługujesz na wiele pochwał. Ma to tę zaletę, że tworzy obiekt funkcji, który można przypisywać do zdarzeń itp. Na przykład: element.onclick = Function ("alert ('test');");
— Ryan Griggs

1
@RyanGriggs W twoim przypadku nie potrzebujesz funkcji "eval", więc lepiej jest napisać jako element.onclick = function() { alert("test"); }.
— Lekensteyn

1
Masz rację z mojego przykładu. Jeśli jednak chcesz przypisać dowolne funkcje przechowywane w łańcuchach, Twoja metoda jest idealna. Właśnie to próbuję zrobić. Mam wiele funkcji przechowywanych w zmiennych łańcuchowych i chcę przypisać jedną do akcji onclick.
— Ryan Griggs

38

Jesteś całkiem blisko.

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

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

//Call the function
test();

Oto działające skrzypce .


Wiedziałem, że funkcja została zadeklarowana, ale nie mogłem odgadnąć nazwy funkcji. Wielkie dzięki.
— ymutlu

4
Obowiązkowe evalostrzeżenie dla przyszłych poszukiwaczy: evalmoże otwierać luki dla hakerów: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/ ... ale jeśli znasz niebezpieczeństwa i potrafisz ich uniknąć, to jest to prosty sposób utwórz funkcję z łańcucha

co jeśli nie masz nazwy funkcji, ponieważ pochodzi ona z rekordu bazy danych?
— Marcel Djaman

13

Tak, używanie Functionjest świetnym rozwiązaniem, ale możemy pójść trochę dalej i przygotować uniwersalny parser, który parsuje ciąg i konwertuje go na prawdziwą funkcję JavaScript ...

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;
    };
}

przykłady użycia:

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

tutaj jest jsfiddle


cześć proszę o wsparcie funkcji strzałek do tej metody?
— satish kumar

1
Otrzymuję ten błąd w typachcirpt „Właściwość 'parseFunction' nie istnieje w typie 'String'.”
— Cegone

11

Dynamiczne nazwy funkcji w JavaScript

Za pomocą 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'

Źródło: http://marcosc.com/2012/03/dynamic-function-names-in-javascript/

Za pomocą eval

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

Za pomocą sjsClass

https://github.com/reduardo7/sjsClass

Przykład

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

var x = new newClassName();
// Next is TRUE
newClassName.name === 'newClassName'

6

Ta technika może być ostatecznie równoważna metodzie eval, ale chciałem ją dodać, ponieważ może być przydatna dla niektórych.

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

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

document.body.appendChild( newCode );

Funkcjonalnie jest to podobne do dodania tego elementu <script> na końcu dokumentu, np .:

...

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

</body>
</html>

3

Użyj new Function()z powrotem do środka i wykonaj go natychmiast.

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

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


1

Przykład z dynamicznymi argumentami:

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]))

Dzięki. Bardzo interesujące
— Дмитрий Васильев
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.