After searching and reading about how to writing Object Oriented JavaScript, I summarized them in the below code:
/********************************************************/
// Enumeration.
var Fruits = {
Apple: 0,
Orange: 1,
Watermelon: 2,
Banana: 3
}; // <-- Don't forget ;
// Using enumeration.
// function SquishFruit(fruit) {
// switch (fruit) {
// case Fruits.Apple : Chop();
// case Fruits.Orange : Pulp();
// case Fruits.Watermelon : Smash();
// case Fruits.Banana : Peel();
// }
/********************************************************/
/********************************************************/
// Base class.
function BaseClass(arg) {
// Constructor.
alert("I am BaseClass constructor.\n arg=" + arg);
// Private fields.
// Use m_privateField, Not this.m_privateField in the class scope.
var m_privateField = "I am BaseClass.m_privateField";
// Public fileds.
// Use this.PublicField, Not PublicField in the class scope.
this.PublicField = "I am BaseClass.PublicField";
// Private methods.
// Invoke PrivateMethod(), Not this.PrivateMethod() in the class scope.
function PrivateMethod(arg) {
alert("I am BaseClass.PrivateMethod.\n arg=" + arg + "\n m_privateField=" + m_privateField);
return;
}
// Public methods.
// ----------------------------------------------------------------------
// Note: Using "prototype" increases efficiency but breaks the encapsulation.
// Example:
// function MyClass() {
// var _value = 1;
// }
// MyClass.prototype.getValue = function () {
// // the function assigned to getValue is
// // no longer in scope with _value it can't access it.
// return _value;
// }
// ----------------------------------------------------------------------
// Invoke this.PublicMethod(), Not PublicMethod() in the class scope.
this.PublicMethod = function (arg) {
alert("I am BaseClass.PublicMethod.\n arg=" + arg + "\n PublicField=" + this.PublicField);
return;
}; // <-- Don't forget ;
// Virtual methods.
// Invoke this.VirtualMethod(), Not VirtualMethod() in the class scope.
this.VirtualMethod = function (arg) {
alert("I am BaseClass.VirtualMethod.\n arg=" + arg + "\n");
return;
}; // <-- Don't forget ;
}
// Static fields.
BaseClass.StaticField = "I am BaseClass.StaticField";
// Static methods.
BaseClass.StaticMethod = function (arg) {
alert("I am BaseClass.StaticMethod.\n arg=" + arg + "\n StaticField=" + BaseClass.StaticField);
return;
}
/********************************************************/
/********************************************************/
// Derived class.
function DerivedClass(arg) {
// Call base class constructor.
// Never forget this call.
BaseClass.call(this, arg);
// Constructor.
alert("I am DerivedClass constructor.\n arg=" + arg);
// Private fields.
// Use m_privateField2, Not this.m_privateField2 in the class scope.
var m_privateField2 = "I am DerivedClass.m_privateField2";
// Public fileds.
// Use this.PublicField2, Not PublicField2 in the class scope.
this.PublicField2 = "I am DerivedClass.PublicField2";
// Private methods.
// Invoke PrivateMethod2(), Not this.PrivateMethod2() in the class scope.
function PrivateMethod2(arg) {
alert("I am DerivedClass.PrivateMethod.\n arg=" + arg + "\n m_privateField2=" + m_privateField2);
return;
}
// Public methods.
// Invoke this.PublicMethod2(), Not PublicMethod2() in the class scope.
this.PublicMethod2 = function (arg) {
alert("I am DerivedClass.PublicMethod2.\n arg=" + arg + "\n PublicField2=" + this.PublicField2);
return;
}; // <-- Don't forget ;
// Virtual methods.
// Invoke this.VirtualMethod(), Not VirtualMethod() in the class scope.
this.VirtualMethod = function (arg) {
alert("I am DerivedClass.VirtualMethod.\n arg=" + arg + "\n");
return;
}; // <-- Don't forget ;
}
// Make DerivedClass derived from BaseClass.
// Never forget these two lines.
// Note: Constructor of BaseClass invoked here.
DerivedClass.prototype = new BaseClass; // () not required!
DerivedClass.prototype.constructor = DerivedClass;
// Static fields.
DerivedClass.StaticField2 = "I am DerivedClass.StaticField2";
// Static methods.
DerivedClass.StaticMethod2 = function (arg) {
alert("I am DerivedClass.StaticMethod2.\n arg=" + arg + "\n StaticField2=" + DerivedClass.StaticField2);
return;
}
/********************************************************/
/********************************************************/
// Tests.
alert("---------- Tests started ----------");
// Test enumuration.
var fruit = Fruits.Apple;
alert("Test enumuration.\n fruit=" + fruit);
// Test BaseClass.
var baseClass = new BaseClass("Hello BaseClass.");
// Test private fields.
alert("Test private fields:\n baseClass.m_privateField=" + baseClass.m_privateField); // undefined.
// Test public fields.
alert("Test public fields:\n baseClass.PublicField=" + baseClass.PublicField);
// Test private methods.
// TypeError: baseClass.PrivateMethod is not a function
// baseClass.PrivateMethod("Hello PrivateMethod.");
// Test public methods.
baseClass.PublicMethod("Hello PublicMethod.");
// Test virtual methods.
baseClass.VirtualMethod("Hello VirtualMethod.");
// Test Static fields.
// Note: Use class name instead of objact name.
// BaseClass.StaticField expression is correct.
// baseClass.StaticField expression is incorrect (baseClass.StaticField value is undefined).
alert("Test Static fields:\n BaseClass.StaticField=" + BaseClass.StaticField);
// Test Static methods.
// Note: Use class name instead of objact name.
BaseClass.StaticMethod("Hello StaticMethod.");
// Test DerivedClass.
var derivedClass = new DerivedClass("Hello DerivedClass.");
// Test private fields.
alert("Test private fields:\n derivedClass.m_privateField=" + derivedClass.m_privateField); // undefined.
alert("Test private fields:\n derivedClass.m_privateField2=" + derivedClass.m_privateField2); // undefined.
// Test public fields.
alert("Test public fields:\n derivedClass.PublicField=" + derivedClass.PublicField);
alert("Test public fields:\n derivedClass.PublicField2=" + derivedClass.PublicField2);
// Test private methods.
// TypeError: derivedClass.PrivateMethod is not a function
// derivedClass.PrivateMethod("Hello PrivateMethod.");
// TypeError: derivedClass.PrivateMethod2 is not a function
// derivedClass.PrivateMethod2("Hello PrivateMethod2.");
// Test public methods.
derivedClass.PublicMethod("Hello PublicMethod.");
derivedClass.PublicMethod2("Hello PublicMethod2.");
// Test virtual methods.
derivedClass.VirtualMethod("Hello VirtualMethod.");
// Test Static fields.
// Note: Use class name instead of objact name.
alert("Test Static fields:\n DerivedClass.StaticField=" + DerivedClass.StaticField); // undefined. Use BaseClass.StaticField.
alert("Test Static fields:\n DerivedClass.StaticField2=" + DerivedClass.StaticField2);
// Test Static methods.
// Note: Use class name instead of objact name.
// TypeError: DerivedClass.StaticMethod is not a function
// DerivedClass.StaticMethod("Hello StaticMethod.");
DerivedClass.StaticMethod2("Hello StaticMethod2.");
/********************************************************/
/********************************************************/
// References:
// http://people.apache.org/~martinc/OOP_with_ECMAScript/
// http://stackoverflow.com/questions/107464/is-javascript-object-oriented
// https://developer.mozilla.org/en-US/docs/JavaScript/Introduction_to_Object-Oriented_JavaScript
// https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Details_of_the_Object_Model
/********************************************************/
I test this code and it works fine.
I test it by IE9, FireFox 15 and Google Chrome 22.
Some of features that I could not implement are:
- Namespaces in human readable form.
- Private static fields.
- Private static methods.
Do I miss any thing about Object Oriented Programming in JavaScript or are there any better idea for Encapsulation, Polymorphism and Inheritance classes?
root object
from which you then expand your code as recommended in the book good parts.. – Anirudha Oct 2 '12 at 17:29