2010-09-22 4 views
8

J'utilisais l'objet littéral pour créer un objet avec des méthodes.
Voici un exemple simple.Littéral d'objet Javascript: initialisation de valeur?

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

Mon problème est que SizeManager.ratio retourne "NaN". Je suis sûr que c'est un problème d'initialisation.
Existe-t-il un moyen d'obtenir une valeur de rapport correcte?
Existe-t-il un moyen d'affecter un costructor ou un initialiseur à un littéral d'objet?
Est-ce que définir un objcet constructeur est le seul moyen?

EDIT: hors cours SizeManager est idéalement un singleton (un seul objet), c'est ainsi que j'utilisais l'objet littéral.

Répondre

24

Oui, c'est un problème d'initialisation. this ne fait pas référence à votre objet SizeManager au moment où vous l'utilisez. (Les initialiseurs d'objet ne modifient pas la valeur de this.) this est défini par la façon dont vous appelez une fonction et a la même valeur tout au long de cet appel de fonction. Vous n'êtes pas appelant n'importe quelle fonction, donc this a la valeur qu'il avait avant le début de ce code.

(je l'ai signalé quelque chose ratio de votre exemple précis à la fin de cela, mais d'abord nous allons marcher à travers quelques options pour le cas général que vous soulevez.)

Daniel's given you un bon boeuf à rendre ratio une fonction sauf qu'il ne semble pas avoir réalisé que vous voulez faire varier la largeur. Par ailleurs, si width et height ne vont pas changer, calculer juste après:

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

(Side note: J'ai ajouté this. aux propriétés que vous référencez dans resize Ils ont été absents de votre original. ., mais ils sont nécessaires Sans eux, vous avez affaire à la horror of implicit globals, ce qui est une mauvaise chose (tm))

Bien sûr, vous pourriez résumer tout cela en une usine.

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); 

... mais vous pourriez aussi bien en faire une fonction constructeur réel de sorte que vous ne créez pas beaucoup de double (mais identique) resize fonctions:

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); 

(note j'ai changé les noms un peu ce dernier.)

Et comme une dernière note finale: Dans votre exemple précis, vous n'avez pas réellement besoin de stocker ratio du tout, vous pouvez le faire:

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

Mais ce qui est juste pour cet exemple précis, d'où la discussion ci-dessus pour parler du cas général.

+2

Si vous passez d'un littéral d'objet à une fonction, vous devez modifier la manière dont vous spécifiez les propriétés (dans le troisième bloc de code). c'est à dire. 'this.width = width' au lieu de' this.width: width' –

+0

@Daniel: Merci! On dirait que je n'ai modifié que partiellement ces lignes après le collage. Fixé. –

5

Votre propriété ratio devrait effectivement être une méthode si vous voulez changer en fonction des changements à width et height:

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

, vous voulez probablement aussi de se référer à this.width et this.height au lieu de width et height dans la méthode resize.

+0

En fonction de modification de taille 'ratio' doit être modifié: this.ratio()' –

+0

Donc, le rapport doit être changé à une méthode et ne peut pas être une propriété. Droite? – bonfo

+0

@Josh Je n'ai pas changé la méthode de redimensionnement, je vais laisser cela à l'OP. Il serait probablement préférable de mettre en cache l'ancien ratio avant de changer la largeur car, avec 'ratio' étant une fonction, la valeur changera après que' this.width' soit changé. –

0

Dans un littéral d'objet, this fait uniquement référence à l'objet littéral lui-même lorsqu'il se trouve dans une fonction. Vous pouvez essayer quelque chose comme ceci au lieu d'un objet littéral; this fera référence à l'objet que vous créez à l'intérieur et à l'extérieur des fonctions.

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; 
    } 
} 

Cela fonctionnera pour un motif singleton. Si vous avez besoin de plus d'un SizeManager, faites-en une fonction de constructeur au lieu d'un objet.

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

* "Dans le littéral d'objet,' this' fait seulement référence à l'objet littéral lui-même quand il se trouve dans une fonction. "* Il n'y a aucun objet littéral ** du tout ** dans votre fragment de code. Il y a une fonction constructeur, que vous appelez immédiatement via 'new', mais il n'y a pas de littéral d'objet. Dans la fonction constructeur, 'this' fait référence au nouvel objet créé par' new' dans le cadre de l'appel de la fonction. –

+0

Après avoir appelé 'resize', le' ratio' sera inexact –

+0

@ T.J. Crowder: Je parlais de l'objet littéral dans son code, pas le mien, évidemment, comme le mien n'en contient pas, comme vous le signalez. Contexte, mec –

Questions connexes