2010-03-11 20 views
8

Aquí es la manera estándar de libros de texto de la descripción de una 'clase' o función constructora en JavaScript, directamente desde el guía definitiva para JavaScript:métodos Fijación al prototipo dentro de la función constructor

function Rectangle(w,h) { 
    this.width = w; 
    this.height = h; 
} 
Rectangle.prototype.area = function() { 
    return this.width * this.height; 
}; 

no lo hago como la manipulación del prototipo colgante aquí, así que estaba tratando de pensar en una forma de encapsular la definición de función para area dentro del constructor. Se me ocurrió con este, lo que hice no esperar a trabajar:

function Rectangle(w,h) { 
    this.width = w; 
    this.height = h; 
    this.constructor.prototype.area = function() { 
     return this.width * this.height; 
    }; 
} 

No esperaba que esto funcione porque la referencia this dentro de la función area debe apuntar a la función area en sí, por lo que no tendría acceso a width y height de this. ¡Pero resulta que sí!

var rect = new Rectangle(2,3); 
var area = rect.area(); // great scott! it is 6 

Algunas pruebas ulterior confirmó que la referencia this dentro de la función area en realidad era una referencia al objeto en construcción, no la función de zona en sí.

function Rectangle(w,h) { 
    this.width = w; 
    this.height = h; 
    var me = this; 
    this.constructor.prototype.whatever = function() { 
     if (this === me) { alert ('this is not what you think');} 
    }; 
} 

Resulta que la alerta aparece, y this es exactamente el objeto en construcción. Entonces, ¿qué está pasando aquí? ¿Por qué this no es el this que espero que sea?

+3

Si tiene cien rectángulos, va a redeclarar ese método de prototipo cien veces. Lo bueno es que solo tienes un método ... – kennebec

+0

Ese es un buen punto. –

Respuesta

5

creo que la respuesta correcta es que no se debe hacer esto porque dicho como Kennebec en el comentario:

Si usted tiene un centenar de rectángulos, que va a redeclare ese método prototipo cien veces .

1

Pensé que 'esto' siempre se refería al objeto contra el que se llamaba la función.

+1

Creo que la respuesta oficial es "depende". –

+0

Para aclarar, 'this' se refiere al objeto a través del cual se invocó la función cuando la función se utiliza como método en un objeto. Este no es el caso aquí. En este caso, la función se invoca como una función y no como un método en un objeto, por lo que 'this' realmente debería referirse al objeto global. –

0

Lo que "esto" apunta a, se determina cuando se ejecuta el código.

Aquí hay una manera fácil de averiguar qué 'esto' debería ser.

Si utiliza '.' para hacer referencia a una función, 'esto' será una referencia a lo que esté en el lado izquierdo de '.'

(Esto no tiene en cuenta .call y .apply)

var myFn = function() { 
return this.name + ' called me'; 
}; 

var me = { 
name : 'oatkiller', 
shoutOut : myFn 
}; 

var you = { 
name : 'Matthew', 
shoutOut : myFn 
}; 

// im on the left of the dot, so this points to me 
me.shoutOut(); // 'oatkiller called me' 

// youre on the left of the dot, so this points to you 
you.shoutOut(); // 'Matthew called me' 
1

El significado de this depende de cómo la función se llama:

  • this por lo general se refiere al objeto de la función es llamado desde el tiempo de ejecución, por ejemplo cuando se llama como ob.foo(), this in foo se referirá a ob.
  • Si se llama a una función en un modo no proporcionado por objeto, p. solo foo(), this se refiere a la variable global (el objeto superior que contiene todas las demás variables globales en su programa js).
  • Y en .call() y .apply(), se proporciona el objeto al que se refiere this.

Ahora, si deseaba una forma de señalar el objeto para la función en la que se creó su función (es decir,, el 2 ° nivel this en el momento de la creación), entonces tendría que cambiar el nombre del this más profundo para hacerlo brillar a través del visible actualmente. Si eso es claro como el barro, esto debería ayudar a aclarar un poco:

function outside() { 
    // Here, 'this' refers to the object outside() is called with. 
    // Let's "rename" this, to make it visible to inside functions. 
    var that = this, 
     private = 42; 

    return { 
     inside: function { 
      // here, 'this' refers to the object inside() is called with, 
      // it is hiding outside's this. 
      // Also, 'that' refers to the object outside() was called with, 
      // *at the time* outside was called and inside was created. 
      // Notice that you can see 'private' 
      // (but nobody outside of 'outside()) can! 
      return private; 
     } 
    } 
} 

Este patrón anterior es útil para crear objetos con métodos públicos que pueden tener acceso a los miembros privados. Ver Crockford para probablemente mejores explicaciones.

0

Creo que estás muy cerca con el último ejemplo. ¿Cómo sobre el uso de un método privilegiado:

function Rectangle(w,h) { 
    this.width = w; 
    this.height = h; 
    var that = this; 
    this.area = function() { 
    return that.width * that.height; 
    } 
} 

var rect = new Rectangle(2,3); 
console.log(rect.area()); 

Ver Crockford's "Private Members in JavaScript" para obtener más información.

Cuestiones relacionadas