2012-07-09 6 views
6

Estoy tratando de entender por qué el siguiente código da como resultado un desbordamiento de la pila cuando se incluyen los paréntesis, pero no cuando se omiten.¿Por qué tengo que omitir paréntesis cuando paso una función como argumento?

Llamo a la función como un argumento para setTimeout y funciona sin parantheses, pero por supuesto falla cuando los agrego. Tuve la intuición de agregar el() después de la función. Solo espero que alguien pueda aclararme esto. ¿Cuándo son parans opcionales y no?

CASO 1:

var a = 1; 

function foo() { 
    a++; 
    document.write(a); 
    setTimeout(foo(), 2000) 
}​ 
// RangeError: Maximum call stack size exceeded 

CASO 2:

var a = 1; 

function foo() { 
    a++; 
    document.write(a); 
    setTimeout(foo, 2000) 
}​ 
// parens are omitted on foo function and it works. 
+0

Probablemente un dup. Esto debería ayudar: http://stackoverflow.com/questions/5520155/settimeout-callback-argument/5520190#5520190 –

+0

muchas gracias lwburk, su explicación en ese enlace lo solucionó todo. –

Respuesta

9

Por lo general, esta pregunta se hace primero con referencia a setTimeout, pero creo que es importante señalar que el comportamiento aquí no es específico de esa función. Simplemente necesita comprender lo que hacen los paréntesis y lo que significa dejarlos fuera.

asumir la función siguiente:

function foo() { 
    return 5; 
} 

Considere las siguientes dos variables declaraciones/asignaciones:

var one = foo(); 
var two = foo; 

¿Qué valores tienen estas variables?

En el primer caso estamos ejecutar la función foo y la asignación de su valor de retorno - el número 5 - a one. En el segundo caso, asignamos foo, más precisamente, una referencia a foo - a two. La función nunca se ejecuta.

Con este conocimiento y la comprensión de que setTimeout espera como primer argumento una referencia a una función, debería ser obvio por qué su primer caso falla, pero funciona la segunda.

Por supuesto, su problema se ve exacerbado por el hecho de que la función que está ejecutando es una llamada recursiva a sí misma. Esto se ejecutará para siempre, para alguna definición de siempre, porque no hay un caso base para finalizar la recursión.

+0

excelente respuesta, gracias. –

+0

Debo preguntar ahora, ¿qué pasaría si quisiera hacer referencia a la función foo con un argumento? p.ej. setTimeout (foo (x), 2000). Ahora entiendo que esto obviamente dará como resultado un desbordamiento de pila, pero ¿es posible pasar un argumento en la primera referencia de función? –

+0

@ChrisM - Sí, en ese caso, lo mejor que puede hacer es pasar una referencia a una función anónima que luego llama a la función deseada. De esta manera: 'setTimeout (function() {foo (x)}, 2000)' –

9

Al escribir

foo() 

que en realidad estás llamando foo en ese momento. Que por supuesto llama a foo() otra vez ... hasta que stackoverflow.

En el caso 2 está pasando efectivamente una "referencia" a foo, diciendo "ejecutar esto en 2s". En realidad no está llamando a foo().

Así que use los paréntesis cuando realmente quiera invocarlos. No cuando quieras consultarlo.

+0

Como ejemplo, intente ejecutar 'var foo = (function() {alert (" Hello ");})' en su consola; luego, intente ejecutar 'var foo = (function() {alert (" Hello ");})()' - observe cómo los parens al final de la declaración invocan realmente la función tan pronto como se define. –

+0

esto tiene mucho sentido para mí ahora. Estaba interpretando los dos argumentos a setTimeout (x, y) como x = qué quieres hacer y y = con qué frecuencia quieres hacerlo. Para mi malentendido, quería llamar y ejecutar foo, y hacerlo cada 2 segundos. ¡gracias por tu respuesta! –

Cuestiones relacionadas