2009-03-24 26 views
138

Tôi đang tìm kiếm một mẹo về điều này. Tôi biết làm thế nào để gọi một chức năng tùy ý động trong Javascript, đi qua các thông số cụ thể, một cái gì đó như thế này:Gọi chức năng động với các thông số động trong Javascript

function mainfunc (func, par1, par2){ 
    window[func](par1, par2); 
} 

function calledfunc(par1, par2){ 
    // Do stuff here 
} 

mainfunc('calledfunc','hello','bye'); 

tôi biết làm thế nào để vượt qua tùy chọn, các thông số không giới hạn sử dụng đối số [] bộ sưu tập bên mainfunc, nhưng, tôi không thể tìm cách gửi số tham số tùy ý đến mainfunc để được gửi đến được gọi là động; làm thế nào tôi có thể thực hiện một cái gì đó như thế này, nhưng với bất kỳ số lượng các đối số tùy chọn (không sử dụng xấu xí nếu-else)? :

function mainfunc (func){ 
    if(arguments.length == 3) 
     window[func](arguments[1], arguments[2]); 
    elseif(arguments.length == 4) 
     window[func](arguments[1], arguments[2], arguments[3]); 
    elseif(arguments.length == 5) 
     window[func](arguments[1], arguments[2], arguments[3], arguments[4]); 
} 

function calledfunc1(par1, par2){ 
    // Do stuff here 
} 

function calledfunc2(par1, par2, par3){ 
    // Do stuff here 
} 

mainfunc('calledfunc1','hello','bye'); 
mainfunc('calledfunc2','hello','bye','goodbye'); 
+2

Tương đương PHP cho 'apply()' là 'call_u ser_func_array() '. Giải pháp http://phpjs.org/functions/call_user_func_array cũng sử dụng nó. – powtac

Trả lời

169

Sử dụng các phương pháp áp dụng của một hàm: -

function mainfunc (func){ 
    window[func].apply(null, Array.prototype.slice.call(arguments, 1)); 
} 

Sửa: Nó xảy ra với tôi rằng điều này sẽ được nhiều hơn nữa hữu ích với một tinh chỉnh nhẹ: -

function mainfunc (func){ 
    this[func].apply(this, Array.prototype.slice.call(arguments, 1)); 
} 

Thao tác này sẽ hoạt động bên ngoài trình duyệt (this mặc định cho không gian toàn cục). Việc sử dụng các cuộc gọi trên mainfunc cũng sẽ làm việc: -

function target(a) { 
    alert(a) 
} 

var o = { 
    suffix: " World", 
    target: function(s) { alert(s + this.suffix); } 
}; 

mainfunc("target", "Hello"); 

mainfunc.call(o, "target", "Hello"); 
+7

đánh bại tôi với nó :) https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Function/apply để biết thêm tài liệu chi tiết – cobbal

+0

Cảm ơn bạn đã liên kết cobbal! Tôi đang đọc (và khám phá) áp dụng phương pháp. – ARemesal

+0

Đây là giải pháp thích hợp nhất, nhưng trong các đối số, nó sẽ bao gồm tên hàm (đối số [0] = 'func'). Tôi có thể tạo ra một mảng với tất cả các đối số ngoại trừ một trong những đối số đầu tiên, và sau đó sử dụng mảng mới này, nhưng, có bất kỳ giải pháp khác mà không sử dụng mảng khác? – ARemesal

-4

thể bạn không chỉ cần vượt qua mảng arguments cùng?

function mainfunc (func){ 
    // remove the first argument containing the function name 
    arguments.shift(); 
    window[func].apply(null, arguments); 
} 

function calledfunc1(args){ 
    // Do stuff here 
} 

function calledfunc2(args){ 
    // Do stuff here 
} 

mainfunc('calledfunc1','hello','bye'); 
mainfunc('calledfunc2','hello','bye','goodbye'); 
+3

Không, bạn không thể, vì "đối số" không phải là mảng mà là đối tượng giống mảng và không có thành viên shift(). Bạn sẽ cần phải sao chép các đối số 1 thành các đối số.length tới một mảng mới và chuyển một đối số đó để áp dụng(). –

13

Bạn có thể sử dụng .apply()

Bạn cần phải xác định một this ... Tôi đoán bạn có thể sử dụng trong vòng thismainfunc.

function mainfunc (func) 
{ 
    var args = new Array(); 
    for (var i = 1; i < arguments.length; i++) 
     args.push(arguments[i]); 

    window[func].apply(this, args); 
} 
+0

đối số không phải là mảng và không có slice thành viên(). –

+0

Rất tiếc, đã quên mất điều đó - đã sửa số – Greg

+0

Bạn không cần phải chuyển đổi 'đối số' thành mảng REAL. Điểm trong điều này là gì? Nó hoạt động hoàn hảo mà không có bước đó ... – James

19

Mã của bạn chỉ hoạt động cho các chức năng toàn cầu, tức là. thành viên của đối tượng window. Để sử dụng nó với chức năng tùy ý, vượt qua các chức năng riêng của mình thay vì tên của nó như là một chuỗi:

function dispatch(fn, args) { 
    fn = (typeof fn == "function") ? fn : window[fn]; // Allow fn to be a function object or the name of a global function 
    return fn.apply(this, args || []); // args is optional, use an empty array by default 
} 

function f1() {} 

function f2() { 
    var f = function() {}; 
    dispatch(f, [1, 2, 3]); 
} 

dispatch(f1, ["foobar"]); 
dispatch("f1", ["foobar"]); 

f2(); // calls inner-function "f" in "f2" 
dispatch("f", [1, 2, 3]); // doesn't work since "f" is local in "f2" 
+2

Điều này làm việc, nhưng bạn nên lưu ý nó không phải là những gì được yêu cầu cho – Greg

12

Dưới đây là những gì bạn cần:

function mainfunc(){ 
    window[Array.prototype.shift.call(arguments)].apply(null, arguments); 
} 

Đối số đầu tiên được sử dụng như tên hàm và tất cả các số còn lại được sử dụng làm đối số cho hàm được gọi ...

Chúng tôi có thể sử dụng phương thức shift để trả về và sau đó xóa giá trị đầu tiên khỏi mảng đối số. Lưu ý rằng chúng tôi đã gọi nó từ nguyên mẫu Array vì, nói đúng, 'đối số' không phải là một mảng thực và do đó không kế thừa phương thức shift như một mảng thông thường.


Bạn cũng có thể gọi phương thức thay đổi như thế này:

[].shift.call(arguments); 
+0

Cảm ơn bạn rất nhiều JimmyP, giải pháp của bạn là tương đương (sau khi chỉnh sửa) để AnthonyWJones ', và bạn đã cho tôi lời khuyên và giải thích tuyệt vời về cách sử dụng Array. nguyên mẫu và []. – ARemesal

+0

Lạ lùng, tôi chắc chắn tôi đã thử điều này và gặp lỗi trong IE – Greg

3

Nếu bạn muốn vượt qua với "lập luận" một vài người khác, bạn phải tạo các mảng của tất cả các đối số với nhau, ví dụ:như thế này:

var Log = { 
    log: function() { 
     var args = ['myarg here']; 
     for(i=0; i<arguments.length; i++) args = args.concat(arguments[i]); 
     console.log.apply(this, args); 
    } 
} 
4

Cách đơn giản nhất có thể là:

var func='myDynamicFunction_'+myHandler; 
var arg1 = 100, arg2 = 'abc'; 

window[func].apply(null,[arg1, arg2]); 

Giả sử, mà chức năng mục tiêu đã được gắn liền với một đối tượng "cửa sổ".

-5

Trong trường hợp ai đó đang vẫn đang tìm kiếm cuộc gọi chức năng động với các thông số động -

callFunction("aaa('hello', 'world')"); 

    function callFunction(func) { 
       try 
       { 
        eval(func); 
       } 
       catch (e) 
       { } 
      } 
    function aaa(a, b) { 
       alert(a + ' ' + b); 
      } 
+2

không không không và không. cũng không. – Kroltan

+0

hạnh phúc gỡ lỗi 10000 dòng đó ... nếu cuộc sống khó khăn, tại sao không làm cho nó khó khăn hơn! – StefanNch

+1

Holy crap, tôi đã thấy gì haha. –

0

Bây giờ tôi đang sử dụng này:

Dialoglar.Confirm = function (_title, _question, callback_OK) { 
    var confirmArguments = arguments; 
    bootbox.dialog({ 
     title: "<b>" + _title + "</b>", 
     message: _question, 
     buttons: { 
      success: { 
       label: "OK", 
       className: "btn-success", 
       callback: function() { 
        if (typeof(callback_OK) == "function") {       callback_OK.apply(this,Array.prototype.slice.call(confirmArguments, 3)); 
        } 
       } 
      }, 
      danger: { 
       label: "Cancel", 
       className: "btn-danger", 
       callback: function() { 
        $(this).hide(); 
       } 
      } 
     } 
    }); 
}; 
-1
function a(a, b) { 
    return a + b 
}; 

function call_a() { 
    return a.apply(a, Array.prototype.slice.call(arguments, 0)); 
} 

console.log(call_a(1, 2)) 

console: 3

Các vấn đề liên quan