How to write JavaScript object definitions
Credit goes to Brandon for pointing this out. Intellisense in VS2010 will work. Export the object definitions out from the function wrapper. As I was working on this, it progressed through 3 options. The first two have lead to option 3, which at the moment is my preferred pattern.
(Option 1)
/* global JsTest */
var JsTest = JsTest || {};
JsTest.Objects = JsTest.Objects || {};
JsTest.Objects = (function () {
"use strict";
var p = {};
p.Rectangle = function (width, height) {
this.width = width;
this.height = height;
};
p.Rectangle.prototype.area = function () {
return (this.width * this.height);
};
p.Rectangle.prototype.circumference = function () {
return ((2 * this.width) + (2 * this.height));
};
p.Square = function (side) {
this.side = side;
};
p.Square.prototype.area = function () {
return this.side * this.side;
};
p.Square.prototype.circumference = function () {
return 4 * this.side;
};
p.Circle = function (radius) {
this.radius = radius;
};
p.Circle.prototype.area = function () {
return (3.14 * (this.radius * this.radius));
};
p.Circle.prototype.circumference = function () {
return (3.14 * (2 * this.radius));
};
return p;
})();
(function () {
"use strict";
var rect1, sq1, cir1, msg;
rect1 = new JsTest.Objects.Rectangle(5, 7);
msg = "Rectangle(" + rect1.width + ", " + rect1.height + ")\n";
msg += "Area: " + rect1.area() + "\n";
msg += "Circumference: " + rect1.circumference() + "\n";
alert(msg);
cir1 = new JsTest.Objects.Circle(8);
msg = "Circle(" + cir1.radius + ")\n";
msg += "Area: " + cir1.area() + "\n";
msg += "Circumference: " + cir1.circumference() + "\n";
alert(msg);
sq1 = new JsTest.Objects.Square(5);
msg = "Square(" + sq1.side + ", " + sq1.side + ")\n";
msg += "Area: " + sq1.area() + "\n";
msg += "Circumference: " + sq1.circumference() + "\n";
alert(msg);
})();
(Option 2:)
/* global JsTest */
var JsTest = JsTest || {};
JsTest.Objects = JsTest.Objects || {};
JsTest.Objects.Rectangle = (function () {
"use strict";
var p = {};
p = function (width, height) {
this.width = width;
this.height = height;
};
p.prototype.area = function () {
return (this.width * this.height);
};
p.prototype.circumference = function () {
return ((2 * this.width) + (2 * this.height));
};
return p;
}());
JsTest.Objects.Square = (function () {
"use strict";
var p = {};
p = function (side) {
this.side = side;
};
p.prototype.area = function () {
return this.side * this.side;
};
p.prototype.circumference = function () {
return 4 * this.side;
};
return p;
}());
JsTest.Objects.Circle = (function () {
"use strict";
var p = {};
p = function (radius) {
this.radius = radius;
};
p.prototype.area = function () {
return (3.14 * (this.radius * this.radius));
};
p.prototype.circumference = function () {
return (3.14 * (2 * this.radius));
};
return p;
}());
(function () {
"use strict";
var rect1, sq1, cir1, msg;
rect1 = new JsTest.Objects.Rectangle(5, 7);
msg = "Rectangle(" + rect1.width + ", " + rect1.height + ")\n";
msg += "Area: " + rect1.area() + "\n";
msg += "Circumference: " + rect1.circumference() + "\n";
alert(msg);
cir1 = new JsTest.Objects.Circle(8);
msg = "Circle(" + cir1.radius + ")\n";
msg += "Area: " + cir1.area() + "\n";
msg += "Circumference: " + cir1.circumference() + "\n";
alert(msg);
sq1 = new JsTest.Objects.Square(5);
msg = "Square(" + sq1.side + ", " + sq1.side + ")\n";
msg += "Area: " + sq1.area() + "\n";
msg += "Circumference: " + sq1.circumference() + "\n";
alert(msg);
}());
(Option 3)
/* global JsTest */
var JsTest = JsTest || {};
JsTest.Objects = JsTest.Objects || {};
JsTest.Objects = (function () {
"use strict";
var p = {};
p.Rectangle = (function () {
var s;
s = function (width, height) {
this.width = width;
this.height = height;
};
s.prototype.area = function () {
return (this.width * this.height);
};
s.prototype.circumference = function () {
return ((2 * this.width) + (2 * this.height));
};
return s;
}());
p.Square = (function () {
var s;
s = function (side) {
this.side = side;
};
s.prototype.area = function () {
return this.side * this.side;
};
s.prototype.circumference = function () {
return 4 * this.side;
};
return s;
}());
p.Circle = (function () {
var s;
s = function (radius) {
this.radius = radius;
};
s.prototype.area = function () {
return (3.14 * (this.radius * this.radius));
};
s.prototype.circumference = function () {
return (3.14 * (2 * this.radius));
};
return s;
}());
return p;
}());
(function () {
"use strict";
var rect1, sq1, cir1, msg;
rect1 = new JsTest.Objects.Rectangle(5, 7);
msg = "Rectangle(" + rect1.width + ", " + rect1.height + ")\n";
msg += "Area: " + rect1.area() + "\n";
msg += "Circumference: " + rect1.circumference() + "\n";
alert(msg);
cir1 = new JsTest.Objects.Circle(8);
msg = "Circle(" + cir1.radius + ")\n";
msg += "Area: " + cir1.area() + "\n";
msg += "Circumference: " + cir1.circumference() + "\n";
alert(msg);
sq1 = new JsTest.Objects.Square(5);
msg = "Square(" + sq1.side + ", " + sq1.side + ")\n";
msg += "Area: " + sq1.area() + "\n";
msg += "Circumference: " + sq1.circumference() + "\n";
alert(msg);
}());
Either define all objects in one closure, and export them to JsTest.Objects (warning: this will overwrite and redefine JsTest.Objects!) or, define each JsTest.Objects.Object in a specific closure, or… a combination of both: one wrapper closure containing all the object definitions, each of which is defined in their own closure.
Matter of programming style?
- Option 1
- It can be difficult just looking at the closure code to separate out the various objects.
- It does allow us share private methods defined in the scope of the closure.
- Option 2
- Somewhat difficult looking at the closure code to decide which object’s code we are looking at. There is a slight effort in looking at the object definition to decide which object definition we are viewing.
- Cannot share private methods.
- Option 3
- Combination of both options 1 & 2. Objects defined in a well contained closures.
- Private methods accessible in the outer closure accessible by object definition inner closures.
- Easy to determine just by looking at the outer closure which object definition we are examining.
A note on the warning: In the earlier post, I had JsTest.Objects.Rectangle defined without using closures (a.k.a. function wrapper). By saying “JsTest.Objects = function () { …” I effectively overwrote the earlier Rectangle definition!!! Note to self: don’t mix styles of defining objects. Pick one, and consistently apply it or risk messing things up!
Leave a comment