2008-10-24 29 views
12

Hoy he tenido una discusión con un colega acerca de las funciones anidadas en Javascript:¿Cuál es el alcance de una función en Javascript/ECMAScript?

function a() { 
    function b() { 
     alert('boo') 
    } 
    var c = 'Bound to local call object.' 
    d = 'Bound to global object.' 
} 

En este ejemplo, los ensayos señalar que b no es accesible fuera del cuerpo de una, al igual que c es. Sin embargo, d es - después de ejecutar a(). Buscando la definición exacta de este comportamiento en el ECMAScript v.3 standard, no encontré la redacción exacta que estaba buscando; lo que la Sec.13 p.71 no dice, es a qué objeto se debe vincular el objeto de función creado por la declaración de declaración de la función. ¿Me estoy perdiendo de algo?

Respuesta

21

Esto es de alcance estático. Las declaraciones dentro de una función tienen un alcance dentro de esa función.

Javascript tiene un comportamiento peculiar, sin embargo, que es que sin el var de palabras clave, que ha implicado una variable global . Eso es lo que estás viendo en tu prueba. Su variable "d" está disponible porque es un global implícito, a pesar de estar escrito dentro del cuerpo de una función.

Además, para responder a la segunda parte de su pregunta: Existe una función en cualquier ámbito que se declare, al igual que una variable.

Sidenote: Probablemente no desee variables globales, especialmente las implícitas. Se recomienda utilizar siempre la palabra clave var para evitar confusiones y mantener todo limpio.

Nota al margen: El estándar ECMA no es probablemente el lugar más útil para encontrar respuestas sobre Javascript, aunque ciertamente no es una mala recursos. Recuerde que javascript en su navegador es solo una implementación de ese estándar, por lo que el documento de estándares le dará las reglas que (en su mayoría) siguieron los implementadores cuando se creó el motor javascript. No puede ofrecer información específica sobre las implementaciones que le interesan, a saber, los principales navegadores. Hay un par de libros en particular que le brindarán información muy directa sobre cómo se comportan las implementaciones de javascript en los principales navegadores. Para ilustrar la diferencia, incluiré extractos a continuación de la especificación ECMAScript y un libro sobre Javascript. Creo que estarás de acuerdo en que el libro da una respuesta más directa.

Aquí es desde el ECMAScript Language Specification:

10,2 Entrando en un contexto de ejecución

Cada función y constructor de llamada entra en un nuevo contexto de ejecución, incluso si una función está llamando a sí mismo recursivamente. Cada devolución sale de un contexto de ejecución . Una excepción lanzada, si no se detecta, también puede salir de uno o más contextos de ejecución.

Cuando el control entra en un contexto de ejecución, la cadena de ámbito se crea y inicializado, instanciación variables se lleva a cabo, y se determina el este valor.

El inicialización de la cadena de ámbito, instanciación variable y la determinación del este valor depende del tipo de código que está siendo introducido.

Aquí es de Javascript: The Definitive Guide (5th Edition) de O'Reilly:

8.8.1 ámbito léxico

Funciones en JavaScript léxica son en lugar de ámbito dinámico. Esto significa que se ejecutan en el alcance en que están definidos, no en el ámbito desde el que se ejecutan. Cuando se define una función , se guarda la cadena actual de alcance y se convierte en parte del estado interno de la función . ...

Muy recomendable para cubrir este tipo de preguntas es el libro de Douglas Crockford:

JavaScript, The Good Parts http://oreilly.com/catalog/covers/9780596517748_cat.gif

Javascript, The Good Parts, también de O'Reilly.

+2

Exactamente a la derecha - en términos generales, 'function a() {}' es equivalente a 'var a = function() {}' (hay algunas diferencias semánticas menores, pero nada demasiado significativo). – olliej

+0

gracias, pero ¿dónde encuentro las siguientes afirmaciones en el estándar ECMAScript (¿o falta?): "Las declaraciones dentro de una función tienen un alcance dentro de esa función". En mi impresión, la semántica de "var a = function() {}" está bien definida, pero no la de la declaración "function a() {...}". –

+0

El estándar ECMAScript solo le dará las pautas para implementar ECMAScript, de las cuales Javascript es solo un miembro de la familia. Entonces no encontrará esa declaración exacta, pero hay otros recursos que pueden ayudarlo. Ver mi nota adicional arriba. – keparo

4

Como yo lo entiendo, estos son equivalentes en lo que se refiere al alcance:

function a() { ... } 

y

var a = function() { ... } 
0

...

function a() { 
    function b() { 
     alert('boo') 
    } 
    var c = 'Bound to local call object.' 
    d = 'Bound to global object.' 
} 

sin ser precedido por var, d es global. Hacer esto a hecho d privada:

function a() { 
    function b() { 
     alert('boo') 
    } 
    var c = 'Bound to local call object.' 
    var d = 'Bound to local object.' 
} 
2

Parece importante señalar que mientras que D está siendo creado como un "global", que es en realidad se está creando como una propiedad del objeto de la ventana. Esto significa que podría sobrescribir inadvertidamente algo que ya existe en el objeto de ventana o que su variable podría no crearse en absoluto. Por lo tanto:

function a() { 
    d = 'Hello World'; 
} 
alert(window.d); // shows 'Hello World' 

Pero no se puede hacer:

function a() { 
    document = 'something'; 
} 

porque no se puede sobrescribir el objeto window.document.

Para todos los propósitos prácticos, puede obtener imágenes de que todo su código se ejecuta en un bloque with(window) gigante.

+0

Sí, este comportamiento se especifica en la Sec. 10.1.9 del estándar ECMAScript. –

1

Javascript tiene dos ámbitos. Global y funcional. Si declara una variable dentro de una función usando la palabra clave "var", será local para esa función y cualquier función interna. Si declara una variable fuera de una función, tiene alcance global.

Finalmente, si omite la palabra clave var cuando se declara por primera vez una variable, javascript asume que desea una variable global, sin importar dónde la declare.

Por lo tanto, llama a la función a, y la función a declara una variable global d.

Cuestiones relacionadas