在搜索并阅读了有关如何编写面向对象的 JavaScript 之后,我将它们总结为以下代码:
/********************************************************/
// 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
/********************************************************/
我测试了这段代码,它工作正常。
我通过 IE9、FireFox 15 和 Google Chrome 22 对其进行了测试。
我无法实现的一些功能是:
- 人类可读形式的命名空间。
- 私有静态字段。
- 私有静态方法。
我是否错过了关于 JavaScript 中的面向对象编程的任何内容,或者对于封装、多态性和继承类有更好的想法吗?