Apakah ada cara untuk membuat fungsi dari string dengan javascript?

107

Sebagai contoh;

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

var fnc = aMethod(s);

Jika ini adalah stringnya, saya ingin fungsi yang disebut fnc. Dan fnc();muncul layar peringatan.

eval("alert(1);") tidak menyelesaikan masalah saya.

ymutlu
sumber

Jawaban:

73

Saya menambahkan tes jsperf untuk 4 cara berbeda untuk membuat fungsi dari string:

  • Menggunakan RegExp dengan kelas Fungsi

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

  • Menggunakan kelas Fungsi dengan "return"

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

  • Menggunakan konstruktor Fungsi resmi

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

  • Menggunakan Eval

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

http://jsben.ch/D2xTG

2 sampel hasil: masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini

phnah
sumber
@Tokopedia Tidak selalu buruk, seperti situasi ini, jsperf sedang down saat ini, untungnya saya menambahkan tangkapan layar hasil sebelum turun, ketika saya mendapat komentar dari Massal.
phnah
@KthProg FYI ini adalah tanggapan terekam yang dihasilkan oleh sistem moderasi :) ini muncul dalam antrian dan kami memeriksa masalah yang telah ditentukan, salah satunya dirancang untuk diperbaiki oleh komentar ini. Ini bukan aturan yang sulit dan cepat, dan Anda akan melihat komentar tersebut dalam bentuk saran, bukan perintah.
Dan Smith
174

Cara yang lebih baik untuk membuat fungsi dari string adalah dengan menggunakan Function:

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

Ini memiliki keuntungan / kerugian bahwa variabel dalam cakupan saat ini (jika tidak global) tidak berlaku untuk fungsi yang baru dibangun.

Meneruskan argumen juga dimungkinkan:

var addition = Function("a", "b", "return a + b;");
alert(addition(5, 3)); // shows '8'
Lekensteyn
sumber
5
Setuju, dengan FunctionAnda tidak mencemari cakupan lokal dan inilah mengapa evalmembuat pengoptimalan menjadi sangat sulit untuk mesin ... Dengan contoh OP, saya akan:var fnc = Function('return '+s)();
CMS
Saya pikir ini mungkin jawaban yang diterima. Ini jauh lebih aman daripada eval ().
Bryan Rayner
Anda, teman saya, berhak mendapatkan banyak suara positif. Ini memiliki keuntungan dalam membuat objek fungsi yang dapat ditugaskan ke acara, dll. Misalnya: element.onclick = Function ("alert ('test');");
Ryan Griggs
1
@RyanGriggs Dalam kasus Anda, Anda tidak memerlukan fungsionalitas "eval" sehingga lebih baik ditulis sebagai element.onclick = function() { alert("test"); }.
Lekensteyn
1
Anda benar dari teladan saya. Namun, jika Anda ingin menetapkan fungsi arbitrer yang disimpan dalam string, metode Anda sempurna. Inilah yang sebenarnya saya coba lakukan. Saya memiliki beberapa fungsi yang disimpan dalam variabel string, dan ingin menetapkan satu fungsi ke onclick.
Ryan Griggs
38

Anda cukup dekat.

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

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

//Call the function
test();

Ini biola yang berfungsi .

James Hill
sumber
saya tahu bahwa fungsi itu dideklarasikan, tetapi tidak bisa menebak untuk memanggil nama fungsi. Terima kasih banyak.
ymutlu
4
evalPeringatan wajib bagi pencari di masa mendatang: evaldapat membuka celah bagi peretas: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… tetapi jika Anda mengetahui bahayanya dan dapat menghindarinya, ini adalah cara sederhana yang bagus untuk membuat fungsi dari string
bagaimana jika Anda tidak memiliki nama fungsi karena berasal dari rekaman database?
Marcel Djaman
13

Ya, menggunakan Functionadalah solusi yang bagus tetapi kita bisa melangkah lebih jauh dan menyiapkan parser universal yang mengurai string dan mengubahnya menjadi fungsi JavaScript nyata ...

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

contoh penggunaan:

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

di sini adalah jsfiddle

Tuan Labu
sumber
hai tolong dukung dukungan fungsi panah untuk metode ini?
sathish kumar
1
Saya menerima kesalahan ini di typescirpt "Properti 'parseFunction' tidak ada pada tipe 'String'."
Cegone
11

Nama fungsi dinamis dalam JavaScript

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

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

Menggunakan eval

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

Menggunakan sjsClass

https://github.com/reduardo7/sjsClass

Contoh

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

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

Teknik ini mungkin pada akhirnya setara dengan metode eval, tetapi saya ingin menambahkannya, karena mungkin berguna bagi sebagian orang.

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

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

document.body.appendChild( newCode );

Ini secara fungsional seperti menambahkan elemen <script> ini ke akhir dokumen Anda, misalnya:

...

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

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

Gunakan new Function()dengan kembali ke dalam dan jalankan segera.

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

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

Fernando Carvajal
sumber
1

Contoh dengan argumen dinamis:

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
sumber
Terima kasih. Sangat menarik
Дмитрий Васильев