Reputation: 12027
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);
Old version of the code. This is working fine. What changes should I make for new one to work?
Upvotes: 1
Views: 76
Reputation: 74204
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/
Upvotes: 1