JavaScript ile bir dizeden işlev oluşturmanın bir yolu var mı?


108

Örneğin;

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

var fnc = aMethod(s);

Eğer dizge buysa, fnc adlı bir fonksiyon istiyorum. Ve fnc();uyarı ekranı açılır.

eval("alert(1);") sorunumu çözmez.

Yanıtlar:


73

Dizeden bir işlev oluşturmanın 4 farklı yolu için bir jsperf testi ekledim:

  • RegExp'i Function sınıfıyla kullanma

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

  • Function sınıfını "return" ile kullanma

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

  • Resmi İşlev yapıcısını kullanma

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

  • Eval kullanma

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

http://jsben.ch/D2xTG

2 sonuç örneği: görüntü açıklamasını buraya girin görüntü açıklamasını buraya girin


@KthProg Chill down;). Her zaman kötü değil, bu durumda olduğu gibi, jsperf şu anda çalışmıyor, neyse ki Bulk'tan yorum aldığımda sonuç ekran görüntülerini düşmeden ekledim.
phnah

@KthProg FYI Bu, denetleme sistemi tarafından oluşturulan hazır bir yanıttı :) bir kuyrukta açılır ve bu yorumun düzeltilmesi için tasarlandığı önceden belirlenmiş sorunları kontrol ederiz. Bu zor ve hızlı bir kural değildir ve yorumun bir komut değil, öneri şeklinde olduğunu fark edeceksiniz.
Dan Smith

175

Bir dizeden işlev oluşturmanın daha iyi bir yolu şunu kullanmaktır Function:

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

Bunun bir avantajı / dezavantajı, mevcut kapsamdaki değişkenlerin (global değilse) yeni oluşturulan fonksiyona uygulanmamasıdır.

Bağımsız değişkenleri aktarmak da mümkündür:

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

5
Katılıyorum, Functionsizinle yerel kapsamı kirletmeyin ve bu nedenle evalmotorlar için optimizasyonu bu kadar zorlaştırıyor ... OP örneğiyle şunu yapardım:var fnc = Function('return '+s)();
CMS

Sanırım bu muhtemelen kabul edilen cevap olmalı. Eval () 'den çok daha güvenlidir.
Bryan Rayner

Sen, arkadaşım, birçok olumlu oyu hak ediyorsun. Bu, olaylara vb. Atanabilen bir işlev nesnesi oluşturma avantajına sahiptir. Örneğin: element.onclick = Function ("alert ('test');");
Ryan Griggs

1
@RyanGriggs Sizin durumunuzda "eval" işlevine ihtiyacınız olmadığı için daha iyi yazılır element.onclick = function() { alert("test"); }.
Lekensteyn

1
Benim örneğimden haklısın. Bununla birlikte, dizelerde depolanan keyfi işlevleri atamak istiyorsanız, yönteminiz mükemmeldir. Aslında yapmaya çalıştığım şey bu. Dize değişkenlerinde depolanan birden fazla işlevim var ve bir onclick işlemine bir tane atamak istiyorum.
Ryan Griggs

38

Oldukça yakınsın.

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

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

//Call the function
test();

İşte çalışan bir keman .


işlevin bildirildiğini biliyordum, ancak işlev adını çağırmayı tahmin edemiyordum. Çok teşekkürler.
ymutlu

4
evalGelecekteki arama yapanlara zorunlu uyarı: evalbilgisayar korsanları için boşluklar açabilir: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… ancak tehlikelerini biliyorsanız ve bunlardan kaçınıyorsanız, bu iyi ve basit bir yoldur. dizeden bir işlev oluşturma

bir veritabanı kaydından geldiği için işlevin adına sahip değilseniz ne olur?
Marcel Djaman

13

Evet, kullanmak Functionharika bir çözüm ama biraz daha ileri gidip dizeyi ayrıştırıp gerçek JavaScript işlevine dönüştüren evrensel ayrıştırıcı hazırlayabiliriz ...

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

kullanım örnekleri:

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

işte jsfiddle


merhaba lütfen bu yöntem için ok işlevi desteğini destekleyin?
sathish kumar

1
Bu hatayı typecirpt'te alıyorum "Özellik 'parseFunction', 'String' türünde mevcut değil."
Cegone

11

Dinamik işlev adları JavaScript

Kullanma 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'

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

Kullanma eval

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

Kullanma sjsClass

https://github.com/reduardo7/sjsClass

Misal

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

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

6

Bu teknik nihayetinde eval yöntemine eşdeğer olabilir, ancak bazıları için yararlı olabileceği için eklemek istedim.

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

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

document.body.appendChild( newCode );

Bu, işlevsel olarak bu <script> öğesini belgenizin sonuna eklemeye benzer, örneğin:

...

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

</body>
</html>

3

new Function()İçeride bir dönüş ile kullanın ve hemen uygulayın.

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

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


1

Dinamik bağımsız değişkenlere sahip bir örnek:

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

Teşekkürler. Çok ilginç
Дмитрий Васильев
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.