Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript object literal: value initialization?

i was using object literal to create an object with methods.
Here a simple example.

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

My issue is that SizeManager.ratio returns "NaN". I'm quite sure it's an initialization issue.
Is there a way to obtain a correct ratio value?
Is there a way to assign a costructor or initializer to an object literal?
Is defining a constructor objcet the only way?

EDIT: off course SizeManager is ideally a singleton (only one object), that's way i was using object literal.

like image 517
bonfo Avatar asked Sep 22 '10 14:09

bonfo


1 Answers

Yes, it's an initialization issue. this does not refer to your SizeManager object at the point you're using it. (Object initializers don't change the value of this.) this is set by how you call a function and has the same value throughout that function call. You're not calling any function there, so this has whatever value it had prior to the beginning of that code.

(I've pointed out something about ratio from your specific example at the very end of this, but first let's walk through a few options for the general case you raise.)

Daniel's given you a good steer on making ratio a function except he doesn't seem to have realized that you want to vary the width. Alternately, if width and height aren't going to change, just calculate it afterward:

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: I've added this. to the properties you're referencing in resize. They were missing from your original, but they're required. Without them, you're dealing with the horror of implicit globals, which is a Bad Thing(tm).)

Of course, you might encapsulate all of that into a factory:

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

...but then you might as well make it an actual constructor function so you don't create lots of duplicate (but identical) resize functions:

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 I changed the names a bit on this last one.)

And as one last final note: In your specific example, you don't actually need to store ratio at all, you could do this:

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

But that's just for that specific example, hence the discussion above to talk about the general case.

like image 110
T.J. Crowder Avatar answered Sep 19 '22 06:09

T.J. Crowder