2009-03-24 16 views
138

Estoy buscando un truco sobre esto. Yo sé cómo llamar a una función dinámica, arbitraria en Javascript, el paso de parámetros específicos, algo como esto:Llamar a la función dinámica con parámetros dinámicos en Javascript

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

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

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

sé cómo pasar parámetros opcionales ilimitadas usando argumentos [] recogida en el interior mainfunc, pero, no se puede calcular cómo enviar un número arbitrario de parámetros a mainfunc para enviarse a calledfunc dinámicamente; ¿Cómo puedo lograr algo como esto, pero con cualquier cantidad de argumentos opcionales (sin usar ese feo if-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

El equivalente de PHP para 'apply()' es 'call_u ser_func_array() '. La solución http://phpjs.org/functions/call_user_func_array también lo usa. – powtac

Respuesta

169

utilizan el método se aplican de una función: -

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

Editar: Se me ocurre que esto sería mucho más útil con una ligera inclinación: -

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

Esto funcionará fuera del navegador (this se predetermina al espacio global). El uso de la llamada en mainfunc también funcionaría: -

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

me gano :) https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Function/apply para obtener más información detallada – cobbal

+0

Gracias por ese enlace cobbal! Estoy leyendo acerca de (y descubriendo) el método de aplicación. – ARemesal

+0

Esta es la solución más adecuada, pero en los argumentos incluirá el nombre de la función (argumentos [0] = 'func'). Puedo generar otra matriz con todos los argumentos excepto la primera, y luego usar esta nueva matriz, pero, ¿hay alguna otra solución que no use otra matriz? – ARemesal

-4

No se pudo que acaba de pasar la matriz a lo largo de arguments?

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, no se puede, ya que "argumentos" no es una matriz, sino un objeto similar a una matriz y no tiene miembro shift(). Debería copiar los argumentos 1 a arguments.length en una nueva matriz y pasar esa a apply(). –

13

Usted podría utilizar .apply()

Es necesario especificar un this ... Creo que se puede utilizar el this dentro 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

argumentos no es una matriz y no tiene miembro slice(). –

+0

Vaya, se olvidó de eso: se corrigió – Greg

+0

No es necesario convertir 'argumentos' en una matriz REAL. ¿Cuál es el punto en esto? Funciona perfectamente sin ese paso ... – James

19

Su código solo funciona para funciones globales, es decir. miembros del objeto window. Para utilizarlo con funciones arbitrarias, pasar a la función en sí en lugar de su nombre como una cadena:

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

Esto funciona, pero debe tener en cuenta que no es lo que se pidió – Greg

12

Esto es lo que necesita:

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

El primer argumento se utiliza como el nombre de la función y todos los restantes se utilizan como argumentos para la función llamada ...

Podemos utilizar el método shift para devolver y luego eliminar el primer valor de la matriz de argumentos. Tenga en cuenta que lo hemos llamado desde el prototipo de matriz, ya que, estrictamente hablando, 'argumentos' no es una matriz real y, por lo tanto, no hereda el método shift como lo haría una matriz común.


También puede llamar al método de desplazamiento de la siguiente manera:

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

Muchas gracias JimmyP, su solución es equivalente (después de la edición) a la de AnthonyWJones, y me dio excelentes consejos y explicaciones sobre el uso de Array. prototipo y []. – ARemesal

+0

Extraño, estoy seguro de que intenté esto y obtuve un error en IE – Greg

3

Si desea pasar con "argumentos" unos a otros, usted tiene que crear la matriz de todos los argumentos en conjunto, es decir,de esta manera:

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

La forma más sencilla podría ser:

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

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

Suponiendo que la función objetivo ya está unido a un objeto "ventana".

-5

En caso de que alguien sigue buscando llamada de función dinámica con parámetros dinámicos -

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

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

no no no y no. también no. – Kroltan

+0

depuración feliz 10000 líneas de eso ... si la vida es difícil, ¿por qué no hacerlo más difícil! – StefanNch

+1

Santa mierda, ¿qué acabo de ver jaja. –

0

Ahora estoy usando esto:

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

consola: 3

Cuestiones relacionadas