2010-09-22 17 views
8

estaba usando objeto literal para crear un objeto con métodos.
Aquí un ejemplo simple.literal de objeto Javascript: inicialización de valor?

var SizeManager = { 
    width : 800, 
    height : 600, 
    ratio : this.width/this.height, 
    resize : function (newWidth) { 
     width = newWidth; 
     height = newWidth/ratio; 
    } 
} 

Mi problema es que SizeManager.ratio devuelve "NaN". Estoy bastante seguro de que es un problema de inicialización.
¿Hay alguna forma de obtener un valor de relación correcto?
¿Hay alguna manera de asignar un costructor o inicializador a un objeto literal?
¿Está definiendo un constructor objcet de la única manera?

EDITAR: fuera de curso, SizeManager es idealmente un singleton (solo un objeto), así es como estaba usando object literal.

Respuesta

24

Sí, es un problema de inicialización. this no se refiere a su objeto SizeManager en el punto en que lo está utilizando. (Los inicializadores de objeto no cambian el valor de this). this se establece por la forma en que llama a una función y tiene el mismo valor a lo largo de esa llamada de función. No está llamando al ninguna función allí, por lo que this tiene el valor que tenía antes del comienzo de ese código.

(he señalado algo sobre ratio de su ejemplo específico al final de este, pero primero vamos a caminar a través de algunas opciones para el caso general se eleva.)

Daniel's given you un buen novillo en hacer ratio una función, excepto que no parece haberse dado cuenta de que desea variar el ancho. Alternativamente, si width y height no van a cambiar, simplemente calcularlo después:

var SizeManager = { 
    width : 800, 
    height : 600, 
    resize : function (newWidth) { 
     this.width = newWidth; 
     this.height = newWidth/this.ratio; 
    } 
}; 
SizeManager.ratio = SizeManager.width/SizeManager.height; 

(Nota al margen: He añadido this. a las propiedades que se está haciendo referencia en resize Ellos habían desaparecido de su original. ., pero son requeridos sin ellos, que está tratando con el horror of implicit globals, que es una mala cosa (tm))

Por supuesto, es posible encapsular todo eso en una fábrica:.

function makeSizeManager(width, height) { 
    return { 
     width : width, 
     height : height, 
     ratio : width/height, 
     resize : function (newWidth) { 
      this.width = newWidth; 
      this.height = newWidth/this.ratio; 
     } 
    }; 
} 
var SizeManager = makeSizeManager(800, 600); 

... pero que también podría hacer que sea una función constructora de real para que no se crea un montón de duplicado (pero idéntico) resize funciones:

function SizeManager(width, height) { 
    this.width = width; 
    this.height = height; 
    this.ratio = width/height; 
} 
SizeManager.prototype.resize = function (newWidth) { 
    this.width = newWidth; 
    this.height = newWidth/this.ratio; 
}; 
var aSizeManagerInstance = new SizeManager(800, 600); 

(tenga en cuenta que los nombres cambian un poco en este último.)

Y como una última nota final: En el ejemplo específico, que en realidad no tienen que almacenar ratio en absoluto, usted puede hacer esto:

var SizeManager = { 
    width : 800, 
    height : 600, 
    resize : function (newWidth) { 
     var ratio = this.width/this.height; 
     this.width = newWidth; 
     this.height = newWidth/ratio; 
    } 
}; 

Pero eso es sólo para ese ejemplo específico, por lo tanto, la discusión anterior para hablar sobre el caso general.

+2

Si lo está cambiando de un objeto literal a una función, debe cambiar la forma en que especifica las propiedades (en el tercer bloque de código). es decir. 'this.width = width' en lugar de' this.width: width' –

+0

@Daniel: ¡Gracias! parece que solo edité a medias esas líneas después de pegarlas. Fijo. –

5

Su propiedad ratio realidad debería ser un método si desea que cambie basado en cambios en width y height:

var SizeManager = { 
    width : 800, 
    height : 600, 
    ratio : function() { 
     return this.width/this.height; 
    }, 
    resize : function (newWidth) { 
     width = newWidth; 
     height = newWidth/ratio; 
    } 
} 

Además, es probable que desee hacer referencia a this.width y this.height en lugar de width y height en el método resize.

+0

En función de cambio de tamaño, 'ratio' necesita ser cambiado a' this.ratio() ' –

+0

Así relación debe ser cambiado a un método y no puede ser una propiedad. ¿Derecha? – bonfo

+0

@Josh No cambié el método de cambio de tamaño, lo dejo en OP. Sin embargo, probablemente sería mejor almacenar en caché la proporción anterior antes de cambiar el ancho, ya que con 'ratio' es una función, el valor cambiará después de que' this.width' se modifique. –

0

En un objeto literal, this solo se refiere a la misma literal del objeto cuando está dentro de una función. Puede intentar algo como esto en lugar de un objeto literal; this se referirá al objeto que está creando tanto dentro como fuera de las funciones.

var SizeManager = new function(){ 
    this.width = 800; 
    this.height = 600; 
    this.ratio = this.width/this.height; 
    this.resize = function (newWidth) { 
     this.width = newWidth; 
     this.height = newWidth/this.ratio; 
    } 
} 

Eso funcionará para un patrón singleton. Si necesita más de un SizeManager, hágalo una función de constructor en lugar de un objeto.

function SizeManager (w, h){ 
    w && (this.width=w); 
    h && (this.height=h); 
    this.ratio = this.width/this.height; 
} 
SizeManager.prototype={ 
    width: 800, 
    height: 600, 
    resize: function (newWidth) { 
    this.width = newWidth; 
    this.height = newWidth/this.ratio; 
    } 
} 
+0

* "En el literal del objeto,' this' solo se refiere a la misma literal del objeto cuando está dentro de una función. "* No hay literal de objeto ** en absoluto ** en su fragmento de código. Hay una función de constructor, a la que llamas inmediatamente a través de 'new', pero no hay un objeto literal. Dentro de la función constructora, 'this' se refiere al nuevo objeto creado por' new' como parte de llamar a la función. –

+0

Después de llamar a 'resize', la 'relación' será inexacta –

+0

@ T.J. Crowder: estaba hablando sobre el objeto literal en su código, no el mío, obviamente, ya que el mío no contiene uno, como usted señala. Contexto, hombre –

Cuestiones relacionadas