1

In the code below, I have a Mass constructor and some methods. Originally, methods were inside the Mass constructor, but there are many methods I'm using. So, to keep things more organized I removed some of the methods outside of the Mass and add them using prototype.

But then I have an issue. I can't reference to Mass with this; it refers to window.

function Mass(elm) {
    this.getElement         = function(element) {
        if (typeof element == "string") {
            return document.getElementById(element);
        }
        return element;
    };
    this.elm                = this.getElement(elm);
    this.elm.style.position = "absolute";
    this.elm.style.left     = 0 + "px";
    this.elm.style.top      = 0 + "px";
    this.updateVars         = function () {
            this.width      = parseInt(this.elm.style.width, 10);
            this.height     = parseInt(this.elm.style.height, 10);
            this.top        = parseInt(this.elm.style.top, 10);
            this.left       = parseInt(this.elm.style.left, 10);
            this.radius     = this.width / 2;
            this.originX    = this.left + this.radius;
            this.originY    = this.top + this.radius;
            this.worldOrgX  = this.originX + parseInt(this.elm.parentNode.style.left, 10);
            this.worldOrgY  = this.originY + parseInt(this.elm.parentNode.style.top, 10);
    };
}

Mass.prototype = {
    // other methods here
    rotation    : {
         // this = window
        mass    : this,
        angle   : 0,
        handler : null,
        rotate  : function (angularVelocity, rotationSpeed) {
                    this.angle = (this.angle + angularVelocity) % 360;
                    // here I need to access Mass.elm and apply rotate
                    this.mass.elm.style.webkitTransform = "rotate(" + this.angle + "deg)";
                },
        start   : function (angularVelocity, rotationSpeed) {
                    var rotation = this; // this = Mass.rotation
                    rotation.handler = setInterval(function () {
                        rotation.rotate(angularVelocity, rotationSpeed);
                    }, rotationSpeed);
                },

    },
}

var earth   = new Mass("earth");
//earth.rotation.start(4.5, 25);

Fiddle

Old version of the code. This is working fine. What changes should I make for new one to work?

akinuri
  • 10,690
  • 10
  • 65
  • 102
  • See if the following is useful: [Preserving a reference to “this” in JavaScript prototype functions](http://stackoverflow.com/questions/2025789/preserving-a-reference-to-this-in-javascript-prototype-functions). – PM 77-1 Jul 05 '14 at 02:01
  • 1
    What made you think that `this` would refer to an instance of `Mass`, if you haven't even created an instance at that moment? `this` is not very complicated, have a look at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this – Felix Kling Jul 05 '14 at 02:10
  • @PM slightly different problem, Mass has a rotation and op needs to know Mass instance in rotation. The value of this in rotation will correctly be rotation (the invoking object) but op doesn't know how to get to the Mass instance from there. – HMR Jul 05 '14 at 02:12
  • You could give each Mass instance a Rotation instance and have a reference to the Mass instance there. More info about constructor functions, prototype and the value of this can be found here. http://stackoverflow.com/questions/16063394/prototypical-inheritance-writing-up/16063711#16063711 – HMR Jul 05 '14 at 02:15

1 Answers1

1

The prototype is not meant to make the code inside your constructor smaller. The prototype is meant to share common functionality. For example your getElement method is the same for all instances of Mass. Hence it would be ideal to put it on the prototype. Same for updateVars.

On the other hand this.rotation is an object and not a function. Every instance of Mass will have a different this.rotation property. Hence this.rotation cannot be shared and hence must not be put on the prototype.

I usually like to create "classes" in JavaScript using a simple defclass function:

function defclass(prototype) {
    var constructor = prototype.constructor;
    constructor.prototype = prototype;
    return constructor;
}

The defclass function unwraps a prototype and returns its constructor. By the way, the constructor is just another method on the prototype.

So here's how I would rewrite your Mass class:

var Mass = defclass({
    constructor: function (id) {
        var element = this.element = this.getElement(id);
        var style = element.style;

        style.position = "absolute";
        style.left = 0;
        style.top = 0;

        this.rotation = new Rotation(this);
    },
    getElement: function (id) {
        if (typeof id !== "string") return id;
        else return document.getElementById(id);
    }
});

Next we create the Rotation class:

var Rotation = defclass({
    constructor: function (mass) {
        this.mass = mass;
        this.angle = 0;
    },
    start: function (angularVelocity, delay) {
        var rotation = this;

        setInterval(function () {
            rotation.rotate(angularVelocity);
        }, delay);
    },
    rotate: function (angularVelocity) {
        var angle = this.angle = (this.angle + angularVelocity) % 360;
        var transform = "rotate(" + angle + "deg)";
        var style = this.mass.element.style;

        style.webkitTransform = transform;
        style.mozTransform = transform;
        style.msTransform = transform;
        style.oTransform = transform;
        style.transform = transform;
    }
});

Finally we simply create an instance of Mass and make it rotate:

var earth = new Mass("earth");
earth.rotation.start(4.5, 25);

See the demo for yourself: http://jsfiddle.net/NL3SJ/

Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
  • Even though I didn't exactly use the method you suggested, it helped me to solve it. It cleared some things.The class term scares me a little. I've created few applications in C# before, but I'm still not that familiar with classes. Anyway, I can access to `Mass` now, and the code looks more organized. Thank you. [**Fiddle**](http://jsfiddle.net/TLzYe/4/) – akinuri Jul 05 '14 at 23:23