Siempre es este un tema difícil de entender, pero se lo puede simplificar viendo cómo funciona el contexto global del objeto window. Por ejemplo, si tenemos esto, el resultado es predecible ya que estamos más acostumbrados a que las cosas sucedan así y por lo tanto todo es más intuitivo:
Código PHP:
var n=0;
function contador2(){
alert(++n);
}
contador2();
contador2();
contador2();
Como n está definida fuera de la función y es global, cada vez que invoquemos a la función estaremos modificando el valor de n. A eso estamos acostumbrados normalmente.
En cambio, si tenemos esto:
Código PHP:
alerta=function(){
var contador=0;
return function(m){
alert('mensaje '+(++contador)+':'+m);
}
}();
alerta('algo');
alerta('algo');
alerta('algo');
alerta('algo');
Ya la cosa puede ser más difícil de predecir. Pero, si asimilamos a la función anónima que envuelve a la segunda función como un contexto semejante a window, seguramente entenderemos que cada vez que se invoque a la función interna estaremos modificando el valor de la variable contador, ya que esa variable, para la función interna, es global. Cada vez que llamamos a la función alerta en realidad estamos llamando a la función interna, pero en su propio contexto: un contexto cerrado, donde las variables conservan valores que sólo pueden modificarse desde ese mismo contexto. Y aquí, la clave para entender el funcionamiento consiste en comparar ese contexto con el contexto global de window.
El intérprete está obligado a guardar en memoria ese nuevo contexto, con todos sus valores, y en los navegadores antiguos existían bugs que impedían que se borraran esos datos incluso al producirse el evento onunload.
En realidad no sé si aclaré u oscurecí. Realmente es un tema siempre difícil de explicar y de entender.