2009-01-27 15 views
159

Entiendo pasar una función a otra función como una devolución de llamada y hacer que se ejecute, pero no entiendo la mejor implementación para hacer eso. Estoy buscando a un ejemplo muy básico, así:Obtener una mejor comprensión de las funciones de devolución de llamada en JavaScript

var myCallBackExample = { 
    myFirstFunction : function(param1, param2, callback) { 
     // Do something with param1 and param2. 
     if (arguments.length == 3) { 
      // Execute callback function. 
      // What is the "best" way to do this? 
     } 
    }, 
    mySecondFunction : function() { 
     myFirstFunction(false, true, function() { 
      // When this anonymous function is called, execute it. 
     }); 
    } 
}; 

En myFirstFunction, si lo hago volver de devolución de llamada nueva(), entonces funciona y ejecuta la función anónima, pero eso no parece ser la correcta acercarse a mí.

+0

correcta en qué sentido? En general, las devoluciones de llamadas se usan para manejadores de eventos, sobre todo llamadas Ajax, que son asíncronas, básicamente cosas donde no se sabe cuándo vendrá (o si) un resposne. – cletus

+2

por cierto, los argumentos son de tipo array pero no de array, por lo que no puedes hacer argument.length pero puedes convertirlo en una matriz usando el método de corte ... – paul

+1

@paul, aunque tienes razón en que 'arguments' no es un array, aún puede hacer referencia a su longitud como 'arguments.length' - pruébelo. Esta propiedad se refiere a la cantidad de argumentos realmente pasados, y no necesariamente a la cantidad de parámetros en la firma de la función. – hotshot309

Respuesta

129

Usted puede simplemente decir

callback(); 

Alternativamente, puede usar el método call si desea ajustar el valor de this dentro de la devolución de llamada.

callback.call(newValueForThis); 

Dentro de la función this sería lo newValueForThis es.

6

Las devoluciones de llamada se refieren a señales y "nuevo" se trata de crear instancias de objeto.

En este caso, sería aún más apropiado ejecutar solo "devolución de llamada();" que "devolver nueva devolución de llamada()" porque de todos modos no está haciendo nada con un valor de retorno.

(Y la prueba arguments.length == 3 es realmente torpe, fwiw, mejor comprobar que existe parámetro de devolución de llamada y es una función.)

34

Hay 3 principales posibilidades para ejecutar una función:

var callback = function(x, y) { 
    // "this" may be different depending how you call the function 
    alert(this); 
}; 
  1. de devolución de llamada (ARGUMENT_1, ARGUMENT_2);
  2. callback.call (some_object, argument_1, argument_2);
  3. callback.apply (some_object, [argument_1, argument_2]);

El método que elija depende de si:

  1. Usted tiene los argumentos almacenados en una matriz o variables distintas.
  2. Desea llamar a esa función en el contexto de algún objeto. En este caso, usar la palabra clave "this" en esa devolución de llamada haría referencia al objeto pasado como argumento en call() o apply(). Si no quiere pasar el contexto del objeto, use nulo o indefinido. En este último caso, el objeto global se usaría para "esto".

Docs para Function.call, Function.apply

6

la aplicación adecuada sería:

if(callback) callback(); 

Esto hace que el parámetro de devolución de llamada opcional ..

+0

¿Qué sucede si el argumento de devolución de llamada no es una función? –

88

Debe comprobar si existe la devolución de llamada, y es una función ejecutable:

if (callback && typeof(callback) === "function") { 
    // execute the callback, passing parameters as necessary 
    callback(); 
} 

Una gran cantidad de bibliotecas (jQuery, ir de discotecas, etc.) utilizar un patrón similar para sus funciones asíncronas, así como nodo .js para todas las funciones asíncronas (nodejs generalmente pasa error y data a la devolución de llamada). ¡Buscar en su código fuente ayudaría!

+0

¿Por qué lanzas 'callback' a la cadena y luego verificas su tipo? ¿Mejorará esto el rendimiento? Esto es como verificar el tipo, verificar si el booleano convertido devuelve verdadero y luego verificar su tipo nuevamente y probarlo con la cadena ... ¿Podría explicar por qué? – headacheCoder

+0

Tengo curiosidad por saber por qué necesitas la primera afirmación para devolución de llamada ... ¿es para verificar nulo o indefinido? ¿No podría 'typeof (devolución de llamada)' lograr eso para usted? 'typeof (null) ===" Objeto "', 'typeof (" undefined ") ===" undefined "' – PJH

+1

Cortocircuito AND. Si la devolución de llamada no existe, no se moleste en calcular su tipo. Sin embargo, tienes razón. No es necesario con el typeof(), pero haré un jsperf y veré si el cortocircuito lo vale. – arunjitsingh

1
function checkCallback(cb) 
{ 
    if(cb || cb!='') 
    { 
     if(typeof window[cb] === 'undefined') alert('Callback function not found.'); 
     else window[cb].call(this,Arg1, Arg2); 
    } 
} 
1

Puede mirar este enlace. Añado un ejemplo básico que explica la función de devolución de llamada en javascript. jsfiddle

var x=0; 

function testCallBack(param1, param2, callback) { 
    alert('param1= ' + param1 + ', param2= ' + param2+' X='+x); 
    if (callback && typeof(callback) === "function") { 
     x+=1; 
     alert("Calla Back x= "+x); 
     x+=1; 
     callback(); 
    } 
} 


testCallBack('ham', 'cheese',function(){ 
alert("Function X= "+x); 
}); 
2

que puede utilizar:

if (callback && typeof(callback) === "function") { 
    callback(); 
} 

el siguiente ejemplo es un poco más amplia:

function mySandwich(param1, param2, callback) { 
alert('Started eating my sandwich.\n\nIt has: ' + param1 + ', ' + param2); 
var sandwich = {toppings: [param1, param2]}, 
    madeCorrectly = (typeof(param1) === "string" && typeof(param2) === "string") ? true : false; 
if (callback && typeof(callback) === "function") { 
    callback.apply(sandwich, [madeCorrectly]); 
    } 
} 

mySandwich('ham', 'cheese', function(correct) { 
if(correct) { 
    alert("Finished eating my " + this.toppings[0] + " and " + this.toppings[1] + " sandwich."); 
} else { 
    alert("Gross! Why would I eat a " + this.toppings[0] + " and " + this.toppings[1] + " sandwich?"); 
    } 
}); 
Cuestiones relacionadas