2010-09-22 20 views
8

Ich verwendete Objektliteral, um ein Objekt mit Methoden zu erstellen.
Hier ein einfaches Beispiel.Javascript Objekt Literal: Wert Initialisierung?

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

Mein Problem ist, dass SizeManager.ratio "NaN" zurückgibt. Ich bin mir ziemlich sicher, dass es sich um ein Initialisierungsproblem handelt.
Gibt es eine Möglichkeit, einen korrekten Verhältniswert zu erhalten?
Gibt es eine Möglichkeit, einem Objektliteral einen Costructor oder Initializer zuzuweisen?
Definiert ein Konstruktor objcet der einzige Weg?

EDIT: natürlich SizeManager ist idealerweise ein Singleton (nur ein Objekt), so habe ich Objektliteral verwendet.

Antwort

24

Ja, es ist ein Initialisierungsproblem. this bezieht sich nicht auf Ihr SizeManager Objekt an dem Punkt, an dem Sie es verwenden. (Objektinitialisierer ändern den Wert this nicht.) this wird durch den Aufruf einer Funktion festgelegt und hat während des Funktionsaufrufs denselben Wert. Sie sind nicht Aufruf jede Funktion dort, so this hat was auch immer es hatte vor dem Anfang dieses Codes.

(Ich habe etwas über ratio von Ihrem spezifischen Beispiel am Ende dieses darauf hingewiesen, aber die ersten durch ein paar Optionen für den allgemeinen Fall, dass Sie heben gehen lassen.)

Daniel's given you eine gute Lenk auf machen ratio eine Funktion, außer er scheint nicht erkannt zu haben, dass Sie die Breite variieren möchten. Alternativ kann, wenn width und height nicht ändern wird, berechnen sie nur danach:

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

(Randbemerkung: Ich this. den Eigenschaften hinzugefügt haben sind Sie in resize Referenzierung Sie wurden von Ihrer ursprünglichen fehlt. ., aber sie sind erforderlich Ohne sie es zu tun Sie mit dem horror of implicit globals, die eine schlechte Sache (tm) ist)

natürlich können Sie all das in einer Fabrik einkapseln könnte.

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

... aber dann könnte man genauso gut ihm eine tatsächliche Konstruktor Funktion, so dass Sie viele doppelte nicht erstellen (aber identisch) resize Funktionen:

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

(Hinweis geändert ich die etwas Namen auf das letzte.

)

Und eine letzte letzte Anmerkung: In Ihrem speziellen Beispiel, brauchen Sie nicht wirklich ratio überhaupt zu speichern, können Sie dies tun:

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

Aber das ist nur für dieses spezielle Beispiel, daher die obige Diskussion, um über den allgemeinen Fall zu sprechen.

+2

Wenn Sie es von einem Objektliteral zu einer Funktion ändern, müssen Sie die Art ändern, wie Sie Eigenschaften angeben (im dritten Codeblock). dh. 'this.width = width' anstelle von' this.width: width' –

+0

@Daniel: Danke! sieht so aus, als ob ich diese Zeilen nach dem Einfügen nur halb bearbeitet habe. Fest. –

5

Ihre ratio Eigenschaft sollte eigentlich eine Methode sein, wenn Sie es basierend auf Änderungen width ändern möchten, und height:

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

Auch Sie wahrscheinlich this.width beziehen möchten und this.height statt width und height in die resize Methode.

+0

In Formatfunktion ausgerüstet, 'muss ratio' zu' this.ratio() ' –

+0

So Verhältnis geändert werden müssen, um ein Verfahren geändert werden und kann nicht eine Eigenschaft sein. Recht? – bonfo

+0

@Josh Ich habe die Größenänderungsmethode nicht geändert, ich überlasse das dem OP. Es wäre wahrscheinlich am besten, das alte Verhältnis zwischenzuspeichern, bevor die Breite geändert wird, denn wenn "Verhältnis" eine Funktion ist, ändert sich der Wert, nachdem "diese.breite" geändert wurde. –

0

In einem Objektliteral bezieht sich this nur auf das Objektliteral selbst, wenn es sich innerhalb einer Funktion befindet. Sie können so etwas anstelle eines Objektliterals versuchen; this bezieht sich auf das Objekt, das Sie sowohl innerhalb als auch außerhalb von Funktionen erstellen.

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

Das wird für ein Singleton-Muster funktionieren. Wenn Sie mehr als einen SizeManager benötigen, stellen Sie eine Konstruktorfunktion anstelle eines Objekts ein.

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

* "Im Objektliteral bezieht sich' this 'nur auf das Objektliteral selbst, wenn es sich innerhalb einer Funktion befindet. "* In Ihrem Code-Snippet gibt es überhaupt kein Objektliteral ** **. Es gibt eine Konstruktorfunktion, die Sie sofort über 'new' aufrufen, aber es gibt kein Objektliteral. Innerhalb der Konstruktorfunktion bezieht sich 'this' auf das neue Objekt, das durch' new' als Teil des Aufrufs der Funktion erzeugt wird. –

+0

Nach Aufruf von 'resize' wird das' ratio' ungenau –

+0

@ T.J. Crowder: Ich habe über das Objekt wörtlich in seinem Code gesprochen, nicht meins, offensichtlich, da meins keinen enthält, wie Sie darauf hinweisen. Kontext, Mann. –

Verwandte Themen