2011-03-05 9 views
5
ejemplo

estoy viendo esta conferencia: http://www.youtube.com/watch?v=Kq4FpMe6cRsEcmaScript 5 Google TechTalk - accidente de Alcance 1

// the speaker states that "'bar' is just some function 
// that invokes whatever function is passed to it" 
function bar(fn) { 
    fn(); 
} 

function foo() { 
    var x = 8; 
    bar(function baz() { return x; }); 
} 

Object.prototype.x = 'foo'; 

En el minuto 35, se presenta el problema anterior se muestra. El conferenciante afirma que algunos buscadores devolverán foo en lugar de 8.

¿Por qué?

Por cierto, al escribir esta pregunta, me di cuenta, pero voy a publicar esta pregunta de todos modos, ya que es un tema interesante. :)


en vivo de demostración:http://jsfiddle.net/simevidas/mHyKc/

Opera 11 alertas 'foo', todos mis otros navegadores (incluyendo IE9) devuelven 8.


Actualización: me retracto de lo que dije de haber dado cuenta de esto. Tiene algo que ver con que la función anidada sea una función nombrada. Si elimina el nombre (baz), entonces Opera devuelve 8, lo que significa que el problema solo ocurre con las funciones anidadas con nombre.

¿Pero por qué?

+0

entiendo el punto de la pregunta, y yo creo que es una distinción importante, pero esta función 'foo' tiene algún código-olor. – zzzzBov

Respuesta

4

Admito que lo busqué. No creo que hubiera descubierto esto fácilmente, por decir lo menos. http://kangax.github.com/nfe/#spidermonkey-peculiarity

Para comprender el problema, es necesaria la semántica de las expresiones de funciones nombradas. Para citar el enlace, "el identificador de una expresión de función nombrada solo está disponible para el alcance local de una función". Concretamente que implica:

var fn = function aNamedFunction() { 
    typeof aNamedFunction; // "function" 
}; 
typeof aNamedFunction; // "undefined" 

Para implementar este comportamiento, SpiderMonkey y otros motores de JS crean un maniquí environment frame entre el marco principal (es decir, el alcance en el que se define la función) y el marco interior de la función, que se crea cada vez que se invoca la función. Este marco ficticio se construye como si se hubiera invocado new Object(), y contiene un mapeo de aNamedFunction al propio objeto de función.

En el ejemplo del código de la pregunta, x se resuelve buscando primero en el marco más interno de la invocación de función. Como el cuerpo de la función no declara var x;, no se encuentra y el intérprete verifica el cuadro un nivel superior, que es el marco ficticio. Como el marco ficticio fue creado por new Object() (o algo semánticamente equivalente), buscar x en el marco ficticio atravesará la cadena del prototipo, como lo hace para cualquier otro objeto JavaScript. Por lo tanto, busca Object.prototype, encuentra la cadena 'foo' vinculada a x y la devuelve.

Gracias a Dios por el alcance léxico consecuente de ES5.

lectura alternativa: http://dmitrysoshnikov.com/ecmascript/chapter-5-functions/#nfe-and-spidermonkey

+0

Ah, sí. Recuerdo haber leído acerca de ese objeto envoltorio en la especificación. Por lo tanto, la resolución del identificador recorrerá la cadena del Alcance para llegar al objeto envoltorio y luego recorrerá la cadena del prototipo del objeto para llegar a x. No me puedo imaginar lo confuso que esto debe ser para los programadores casuales de JavaScript ':)' –

Cuestiones relacionadas