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.