Có cách nào để tạo một hàm từ một chuỗi bằng javascript không?


107

Ví dụ;

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

var fnc = aMethod(s);

Nếu đây là chuỗi, tôi muốn một hàm được gọi là fnc. Và fnc();màn hình cảnh báo bật lên.

eval("alert(1);") không giải quyết được vấn đề của tôi.

Câu trả lời:


73

Tôi đã thêm một bài kiểm tra jsperf cho 4 cách khác nhau để tạo một hàm từ chuỗi:

  • Sử dụng RegExp với lớp chức năng

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

  • Sử dụng lớp Chức năng với "return"

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

  • Sử dụng hàm tạo hàm chính thức

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

  • Sử dụng Eval

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

http://jsben.ch/D2xTG

2 mẫu kết quả: nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây


@KthProg Bình tĩnh đi;). Không phải lúc nào cũng tệ, như tình huống này, hiện tại jsperf bị sập nguồn, may mắn là mình đã thêm ảnh chụp màn hình kết quả trước khi nó bị sập, khi nhận được comment từ Bulk.
phnah

@KthProg FYI đây là một phản hồi soạn trước được tạo ra bởi hệ thống kiểm duyệt :) nó bật lên trong một hàng đợi và chúng tôi kiểm tra các vấn đề đã xác định trước, một trong số đó là nhận xét này được thiết kế để khắc phục. Đây không phải là một quy tắc khó và nhanh chóng, và bạn sẽ nhận thấy nhận xét ở dạng gợi ý chứ không phải lệnh.
Dan Smith

174

Cách tốt hơn để tạo một hàm từ một chuỗi là sử dụng Function:

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

Điều này có ưu điểm / nhược điểm là các biến trong phạm vi hiện tại (nếu không phải là toàn cục) không áp dụng cho hàm mới được xây dựng.

Việc chuyển đối số cũng có thể:

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

5
Đồng ý, với việc Functionbạn không gây ô nhiễm phạm vi cục bộ và đây là lý do tại sao evalviệc tối ưu hóa rất khó khăn cho các động cơ ... Với ví dụ OP, tôi sẽ:var fnc = Function('return '+s)();
CMS

Tôi nghĩ đây có lẽ nên là câu trả lời được chấp nhận. Nó an toàn hơn nhiều so với eval ().
Bryan Rayner

Bạn, bạn của tôi, xứng đáng nhận được nhiều sự ủng hộ. Điều này có lợi thế là tạo ra một đối tượng hàm có thể được gán cho các sự kiện, v.v. Ví dụ: element.onclick = Function ("alert ('test');");
Ryan Griggs

1
@RyanGriggs Trong trường hợp của bạn, bạn không cần chức năng "eval" vì vậy tốt hơn nên viết là element.onclick = function() { alert("test"); }.
Lekensteyn

1
Bạn đúng từ ví dụ của tôi. Tuy nhiên, nếu bạn muốn gán các hàm tùy ý được lưu trữ trong chuỗi, phương pháp của bạn là hoàn hảo. Đây là những gì tôi thực sự đang cố gắng làm. Tôi có nhiều hàm được lưu trữ trong các biến chuỗi và muốn gán một hàm cho một hành động onclick.
Ryan Griggs

38

Bạn khá gần gũi.

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

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

//Call the function
test();

Đây là một công việc khó khăn .


tôi biết rằng hàm đã được khai báo, nhưng không thể đoán để gọi tên hàm. Cảm ơn rất nhiều.
ymutlu

4
evalCảnh báo bắt buộc cho những người tìm kiếm trong tương lai: evalcó thể mở sơ hở cho tin tặc: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… nhưng nếu bạn biết những nguy hiểm của nó và có thể tránh chúng, thì đây là một cách đơn giản hay để tạo một hàm từ một chuỗi

điều gì sẽ xảy ra nếu bạn không có tên của hàm vì nó đến từ một bản ghi cơ sở dữ liệu?
Marcel Djaman

13

Vâng, sử dụng Functionlà một giải pháp tuyệt vời nhưng chúng ta có thể đi xa hơn một chút và chuẩn bị trình phân tích cú pháp phổ quát để phân tích cú pháp chuỗi và chuyển đổi nó thành hàm JavaScript thực ...

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

ví dụ về cách sử dụng:

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

đây là jsfiddle


xin vui lòng hỗ trợ chức năng mũi tên hỗ trợ phương pháp này?
sathish kumar

1
Tôi nhận được lỗi này trong stylescirpt "Thuộc tính 'parseFunction' không tồn tại trên loại 'Chuỗi'."
Cegone

11

Tên hàm động trong JavaScript

Sử dụng 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'

Nguồn: http://marcosc.com/2012/03/dynamic- Chức năng-names-in-javascript/

Sử dụng eval

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

Sử dụng sjsClass

https://github.com/reduardo7/sjsClass

Thí dụ

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

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

6

Kỹ thuật này cuối cùng có thể tương đương với phương thức eval, nhưng tôi muốn thêm nó, vì nó có thể hữu ích cho một số người.

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

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

document.body.appendChild( newCode );

Điều này có chức năng giống như thêm phần tử <script> này vào cuối tài liệu của bạn, ví dụ:

...

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

</body>
</html>

3

Sử dụng new Function()với trở lại bên trong và thực thi nó ngay lập tức.

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

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


1

Một ví dụ với các đối số động:

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

Cảm ơn. Rất thú vị
Дмитрий Васильев
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.