-1

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?

Amir Saniyan
  • 13,014
  • 20
  • 92
  • 137
  • 1
    you should have a `root object` from which you then expand your code as recommended in the book good parts.. – Anirudha Oct 02 '12 at 17:29
  • The semicolon after the closing brace of an object initializer is not actually required as implied by your comment. – lanzz Oct 02 '12 at 17:34

1 Answers1

2

This is a good structure in JavaScript I use that has good encapsulation and abstraction.

    var musicPlayer = {
               init: function(target_items, name){
                  //do something
                  anotherFunction('test');
                },
                anotherFunction(argument){
                }
    };
    $(document).ready(function(){
         musicPlayer.init('.container', 'tooltip');

    });
Josh Bedo
  • 3,410
  • 3
  • 21
  • 33