2010-04-23 7 views
8

este es uno de los más característica de misterio en JavaScript, después de asignar el método de objeto a otra variable, la unión (esta palabra clave) se pierdefunción de JavaScript vinculante (esta palabra clave) se pierde después de la asignación

var john = { 
    name: 'John', 
    greet: function(person) { 
    alert("Hi " + person + ", my name is " + this.name); 
    } 
}; 

john.greet("Mark"); // Hi Mark, my name is John 

var fx = john.greet; 
fx("Mark"); // Hi Mark, my name is 

mi pregunta es:

1) ¿Qué está sucediendo detrás de la tarea? var fx = john.greet; es esta copia por valor o copia por referencia? fx y john.greet apuntan a dos funciones diferentes, ¿no?

2) ya que fx es un método global, la cadena de alcance contiene solo un objeto global. ¿cuál es el valor de esta propiedad en ¿Objeto variable?

+0

La encuadernación no está "perdida"; nunca estuvo allí en primer lugar. En cualquier expresión de JavaScript 'foo.bar()', 'this' en el contexto de la función' bar() 'será' foo', independientemente de dónde se haya declarado 'bar' o cómo se asoció con' foo' '. –

Respuesta

5

1) fx y john.greet estamos refiriendo a la misma objeto de función, la operación de asignación para los objetos, que funciona por referencia.

Para valores primitivos, como String, Number, Booleanundefined o null, se hará una copia del valor.

2) El valor this se refiere al objeto global.

El valor this no es una propiedad de la Variable Object y no tiene nada que ver con la cadena alcance, es una palabra reservada especial, y se determina de forma implícita cuando un function is called (también se puede establecer de manera explícita a través de call o apply).

JavaScript maneja internamente un Reference type, que consta de dos componentes, el objeto base de y el nombre propiedad, cuando se invoca una función, el valor this se determina implícitamente por conseguir el objeto base de (por el operación interna GetValue).

Y finalmente, el último caso, si se establece implícitamente this es cuando se invoca una función con el operador new, la palabra clave this hará referencia a un objeto recién creado.

Así que en resumen, aquí es cómo funciona thisimplícitamente:

1- Cuando se invoca una función como un método (la función es invocada como miembro de un objeto):

obj.method(); // 'this' inside method will refer to obj 

2- A normal de llamada función:

myFunction(); // 'this' inside the function will refer to the Global object 
// or 
(function() {})(); 

3- Cuando t que new operador se utiliza:

var obj = new MyObj(); // 'this' will refer to a newly created object. 
3

Según tengo entendido, solo está asignando ese método a la variable "fx". El contexto del objeto john no lo acompaña.

En la parte superior de mi cabeza, "esto" en el contexto de fx se referirá al objeto global, que en el contexto de un navegador es (creo) equivalente a su objeto de ventana.

(edición para aclarar objeto global. Una especie de)

+0

Correcto, porque el objeto global es 'ventana', por lo que un' foo' no calificado siempre significa 'window.foo' (a menos que lo hayas localizado más localmente usando' var'). –

+0

esto se referirá a lo que está llamando al método, implícita o explícitamente con 'call' o' apply'. –

13

john.greet("Mark") llama en realidad una función. Cuando lo haces var fx = john.greet;, estás obteniendo una referencia a la función. Entonces cuando lo llamas, this no está limitado a john. Lo que realmente está haciendo es window.fx("Mark") y entonces this es el objeto window. Estabas en el camino correcto cuando dijiste que estaba en el contexto global. En esta instancia particular, el objeto global es window, por lo que fx es en realidad window.fx.

Cuando tenga una función de referencia, debe usar call o apply si desea establecer el valor de this. Trate de hacer esto:

fx.call(john, "Mark"); 

El primer argumento en call o apply es el valor utilizado para this en el contexto de la llamada de función.

EDITAR

Algunas personas mencionaron que el verdadero problema aquí podría ser la confusión que rodea a un objeto literal contra una instancia de un objeto. Está creando un objeto literal que también se comporta como un singleton. No puedes crear una nueva instancia de ese objeto. En este caso, john es una referencia a ese objeto literal. En ese contexto, this en la función greet se refiere a la misma literal del objeto. Por lo tanto, cuando llame al john.greet("Mark"), this está obligado a john.

Cuando agarras una referencia a john.greet sólo por sí mismo y asignarlo a una variable global, básicamente estás haciendo esto:

var fx = function(person) { 
    alert("Hi " + person + ", my name is " + this.name); 
} 

En este escenario, es thiswindow, porque fx es básicamente window.fx (ya que el objeto global aquí es window. Suponiendo que este código estuviera dentro de otra función, el objeto global se referiría a esa función.

Si desea crear varias instancias de un objeto, se puede hacer algo como esto:

var Person = function(name) { 
    var self = this; //maintains a reference to the instance 

    this.name = name; 
    this.greet = function(name) { 
     alert("Hi " + name + ", my name is " + self.name); 
    } 
} 

var john = new Person("John"); 
john.greet("Mark"); // alerts "Hi Mark, my name is John" 

var fx = john.greet; 
fx("Mark"); // also alerts "Hi Mark, my name is John" 

Aquí, la variable self (que es local a la función) mantiene una referencia a la instancia real porque eres uniéndolo al this cuando crea el objeto.

Existen muchas mejores prácticas asociadas con OOP en Javascript. Puedes buscar y encontrar Google (hay muchos enlaces). Recomiendo leer cosas de Douglas Crockford especialmente.

+0

+1 para la explicación de la función 'llamada'. –

+0

sí, buena mención de.llamada, que realmente resolverá el problema 8) – Funkatron

+0

@funkatron - el problema está mucho más arraigado que la manera en que se llama el método. Responder una pregunta como está escrito es una buena práctica. Ser capaz de determinar cuándo el interlocutor no comprende su propia pregunta o problema también es bueno. –

1

Debido a que sólo está configurando fx con el método de saludo y no a todo el john objeto, que no tiene el concepto de que es padre y se convierte en un ámbito global. Entonces, en esencia, está pasando de un valor en que solo copia el método.

Dado que la función ahora tiene un alcance global, "this" se convierte en el objeto Window.

Si en su lugar configuras fx a john, obtienes lo que se espera.

var john = { 
    name: 'John', 
    greet: function(person) { 
    alert("Hi " + person + ", my name is " + this.name); 
    } 
}; 

john.greet("Mark"); // Hi Mark, my name is John 

var fx = john; 
fx.greet("Mark"); // Hi Mark, my name is John 
0

inspirado en @Vivin Paliath respuesta, de hecho, salgo algo nuevo. En cuanto a mí, siempre hago mi mejor esfuerzo para hacer la programación javascript de la misma manera que java, especialmente en OOP.

Así que mi sugerencia es evitar el uso este tan posible como podemos, cuando nos hacemos

var self = this; 

debemos utilizar uno mismo en lugar de esto en toda la función (función prototipo, en absoluto), pero si escribimos algo como esto:

function MyObject = { 
    var self = this; 
}; 

MyObject.prototype = { 
    method1 = function(data){ 
     self.data = data; 
    } 
} 

esto no va a funcionar, porque prototipo es un objeto en MiObjeto, no puede acceder privada miembro de self propiedad de MyObject. Mi solución para esto es simple:

function MyObject = { 
    var self = this; 
    MyObject.prototype.method1 = function(data){ 
     self.data = data; 
    }; 
} 

Esto lleva a la ventaja de la eficiencia del prototipo y también que no tiene que preocuparse por todos los esta cuestiones. Aunque vamos a escribir un montón de MyObject.prototype.xxxx cosa.

Si esto útil para sus chicos, por favor, dame un poco pulgar hacia arriba, por lo que puede reunir a 15 reputación el pulgar para arriba que otros, gracias.

Cuestiones relacionadas