2010-07-18 17 views
6

Estuve trabajando en un proyecto por un tiempo, tratando de descubrir lo que estaba haciendo mal, cuando finalmente reduje "el error" al hecho de que el código siguiente no funciona como esperaba:'este' objeto no se puede acceder en funciones privadas de JavaScript sin un truco?

function Alpha() 
    { 
    this.onion = 'onion'; 

    function Beta() 
     { 
     alert(this.onion); 
     } 

    Beta(); 
    } 

alpha1 = new Alpha(); 
// Alerts 'undefined' 

Sin embargo, si cambio el código para esto:

function Alpha() 
    { 
    var self = this; 
    this.onion = 'onion'; 

    function Beta() 
     { 
     alert(self.onion); 
     } 

    Beta(); 
    } 

alpha1 = new Alpha(); 
// Alerts 'onion' 

funciona como yo esperaría. Después de desperdiciar una gran parte de mi vida, ¿alguien puede explicar por qué funciona así?

Respuesta

11

Funciona de esta manera porque cada función ha asociado su propio contexto de ejecución .

Sin embargo, hay otras maneras de hacerlo, por ejemplo:

Uso call o apply para invocar la función:

function Alpha() { 
    this.onion = 'onion'; 

    function Beta() { 
    alert(this.onion); 
    } 

    Beta.call(this); 
} 

var alpha1 = new Alpha(); 
// Alerts 'onion' 

El nuevo ECMAScript quinta edición estándar, introduce una manera de mantener la función contexto, el método Function.prototype.bind:

function Alpha() { 
    this.onion = 'onion'; 

    var Beta = function() { 
    alert(this.onion); 
    }.bind(this); 

    Beta(); 
} 

var alpha1 = new Alpha(); 
// Alerts 'onion' 

Podemos decir que la función Beta es enlazada, y no importa cómo la invoque, su valor this estará intacto.

Este método no es ampliamente compatible todavía, actualmente solo IE9pre3 lo incluye, pero puede incluir an implementation para que funcione ahora.

Ahora voy a extenderme sobre cómo this obras: existen

El valor this en cada execution context, y por el código de función se establece implícitamente cuando se hace una llamada a la función, se determina el valor en función de cómo la referencia si formado.

En su ejemplo, cuando se invoca Beta();, ya que no está vinculado a ningún objeto, podemos decir que la referencia no tiene un objeto de base , entonces, el valor this se referirá al objeto global.

Otro caso ocurre cuando se invoca una función que está enlazado como una propiedad de un objeto, por ejemplo:

var obj = { 
    foo: function() { return this === obj;} 
}; 
obj.foo(); // true 

Como se puede ver, la referencia que se invoca obj.bar(); contiene un objeto de base, que es obj y el valor this dentro de la función invocada se referirá a él.

Nota: El reference type es un concepto abstracto, se define a efectos de ejecución lenguaje se pueden ver los detalles en la especificación.

Un tercer caso en el que el valor this se establece implícitamente es cuando se utiliza el operador new, se refiere a un objeto de nueva creación que hereda de prototipo de su constructor:

function Foo() { 
    return this; // `this` is implicitly returned when a function is called 
}    // with `new`, this line is included only to make it obvious 

var foo = new Foo(); 
foo instanceof Foo; // true 
Foo.prototype.isPrototypeOf(foo); // true 
+0

+1. Más completo que nunca. –

+0

¡Gracias @Tim! – CMS

2

Cuando llama a una función que no es miembro (no se llama como someObject.method()), se ejecuta en el contexto de la ventana. No importa si se trata de una función privada o global.

que podría hacer:

call le permite llamar a una función al pasar de un contexto como el primer argumento (apply es similar, pero la lista de argumentos es una matriz).

Sin embargo, no estoy seguro (incluso para el ejemplo trivial) de por qué la cebolla es pública, pero Beta es privada.

+0

pero si lo hiciera: var Beta = function() {alert (self.onion);}, daría el mismo resultado, aunque Beta sea un miembro privado. – Nick

+0

Aún no es una función miembro. Las funciones de miembros de JavaScript son públicas. –

+0

Hmm ... bien, confundirse con la terminología. Pero Beta es un miembro privado (cuyo valor es una Función), simplemente no es una función miembro ¿verdad? – Nick

8

De JavaScript: The Definitive Guide, 5th Edition (el rinoceronte libro):

Cuando se invoca una función como una función más que como un método, el this palabra clave se refiere a la glo bal objeto. Confusamente, esto es cierto incluso cuando se invoca una función anidada (como una función) dentro de un método que contiene que se invoca como un método: la this palabra clave tiene un valor en la función pero (counterintuitively) se refiere a que contiene el objeto global dentro del cuerpo de la función anidada .

Tenga en cuenta que this es una palabra clave, no una variable o el nombre de la propiedad. JavaScript sintaxis no le permite asignar un valor de a this.

Dos cosas que prestar atención a aquí:

  1. this no es una variable, por lo que las reglas de captación de cierre normales no se aplican.
  2. this es un "rebote" en cada llamada de función, ya sea como un método, una llamada a función normal o vía new. Como está realizando una llamada a función normal (al llamar a Beta), this se está vinculando al "objeto global".
Cuestiones relacionadas