2009-03-24 17 views
138

Sto cercando un trucco per questo. Io so come chiamare una dinamica, funzione arbitraria in Javascript, il passaggio di parametri specifici, qualcosa di simile:Chiamare la funzione dinamica con parametri dinamici in Javascript

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

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

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

so come passare opzionali, i parametri illimitata usando argomenti collezione [] all'interno mainfunc, ma, non riesco a capire come inviare un numero arbitrario di parametri a mainfunc da inviare a callfunc dinamicamente; come posso realizzare qualcosa del genere, ma con un numero qualsiasi di argomenti opzionali (non usare quel brutto se-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

L'equivalente PHP per 'apply()' è 'call_u ser_func_array() '. Lo usa anche la soluzione http://phpjs.org/functions/call_user_func_array. – powtac

risposta

169

utilizzare il metodo applicano di una funzione: -

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

Edit: mi viene in mente che questo sarebbe molto più utile con un leggero ritocco: -

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

Questo funzionerà al di fuori del browser (this predefinito nello spazio globale). L'uso di chiamata su mainfunc potrebbe anche funzionare: -

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

picchiami :) https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Function/apply per documentazione più dettagliata – cobbal

+0

Grazie per il link cobbal! Sto leggendo (e scoprendo) il metodo di applicazione. – ARemesal

+0

Questa è la soluzione più adeguata, ma negli argomenti includerà il nome della funzione (argomenti [0] = 'func'). Posso generare un altro array con tutti gli argomenti tranne il primo, e quindi usare questo nuovo array, ma ci sono altre soluzioni che non usano altri array? – ARemesal

-4

Impossibile basta passare la matrice arguments lungo?

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

No, non è possibile, poiché "argomenti" non è un array ma un oggetto simile ad un array e non ha un membro shift(). Dovresti copiare gli argomenti 1 in arguments.length in un nuovo array e passare quello da applicare(). Gli argomenti –

13

Si potrebbe utilizzare .apply()

È necessario specificare un this ... Credo che si potrebbe utilizzare il this all'interno mainfunc.

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

non sono un array e non hanno slice membro(). –

+0

Oops, ho dimenticato questo - risolto – Greg

+0

Non hai bisogno di convertire 'argomenti' in un array REAL. Qual è il punto in questo? Funziona perfettamente senza quel passo ... – James

19

Il tuo codice funziona solo per funzioni globali, es. membri dell'oggetto window. Per usarlo con funzioni arbitrarie, passare la funzione stessa invece del suo nome come una stringa:

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

Funziona, ma dovresti notare che non è quello che è stato chiesto per – Greg

12

Ecco quello che vi serve:

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

Il primo argomento viene utilizzato come nome della funzione e tutti i rimanenti vengono utilizzati come argomenti per la funzione chiamata ...

Siamo in grado di utilizzare il metodo shift per restituire e quindi eliminare il primo valore dalla matrice di argomenti. Si noti che l'abbiamo chiamato dal prototipo di Array poiché, in senso stretto, "argomenti" non è un vero array e quindi non eredita il metodo shift come un normale array.


È possibile anche chiamare il metodo di spostamento in questo modo:

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

Grazie mille JimmyP, la tua soluzione è equivalente (dopo la modifica) a quella di AnthonyWJones, e mi hai dato ottimi consigli e spiegazioni sull'utilizzo di Array. prototipo e []. – ARemesal

+0

Strano, sono sicuro di averlo provato e ho ricevuto un errore in IE – Greg

3

Se volete passare con "argomenti" pochi altri, è necessario creare la matrice di tutti gli argomenti insieme, vale a direin questo modo:

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

Il modo più semplice potrebbe essere:

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

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

Supponendo che la funzione obiettivo è già collegato a un oggetto "finestra".

-5

Nel caso in cui qualcuno sta ancora cercando chiamata di funzione dinamica con parametri dinamici -

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

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

no no no e no. anche no. – Kroltan

+0

debug felice di 10000 righe di quello ... se la vita è dura, perché non renderla più difficile! – StefanNch

+1

Santa merda, cosa ho appena visto haha. –

0

Ora sto usando questo:

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

Problemi correlati