我是一个由衷的面向对象的程序员,并且JavaScript支持基于继承的原型(prototype)。不幸的是这会导致冗长的类定义:

function Animal(name) {};
 
Animal.prototype.eat = function() {};
 
Animal.prototype.say = function(message) {

 

    我希望能有一个良好的关于JavaScript OO的基础类:
  • 我希望能简单的创建类而没有MyClass.prototype 的冗余代码。
  • 我希望有能够直接访问被重载函数的函数重载 (就像 Java的super)
  • 我希望在原型构造阶段能够避免调用类的构造方法。
  • 我希望能简单的添加静态的(类)属性和函数。
  • 我希望不依靠全局函数创建原型链的方式,达到上述的目的。
  • 我希望能够不用令人同情的 Object.prototype达到上述目的。
Base类

    我已经创建了一个JavaScript的类(Base.js),我希望(能通过它)简轻JavaScript OO给我们带来的痛苦(确实比较痛苦)。这是一个简单的类,它通过添加了两个实例函数和一个类函数扩展了Object对象。

Base类定义了两个实例方法:

extend:调用这个方法,可以用另一个接口来扩展一个对象:
var object = new Base;
 
object.extend({

 
  value: "some data",
 
  method: function() {

 
    alert("Hello World!");
 
  }
 
});
 
object.method();
 
// ==> Hello World!
 

base:如果某个方法被重载了,通过base方法可以访问被重载方法:
var object = new Base;
 
object.method = function() {

 
  alert("Hello World!");
 
};
 
object.extend({

 
  method: function() {

 
    // call the "super" method

 
    this.base();
 
    // add some code

 
    alert("Hello again!");
 
  }
 
});
 
object.method();
 
// ==> Hello World!
 
// ==> Hello again!
 

    你也可以在一个构造函数内调用base方法。
创建类

    通过调用Base类里面的extend方法,可以创建类:

var Animal = Base.extend({

 
  constructor: function(name) {

 
    this.name = name;
 
  },
 
  
 
  name: "",
 
  
 
  eat: function() {

 
    this.say("Yum!");
 
  },
 
  
 
  say: function(message) {

 
    alert(this.name + ": " + message);
 
  }
 
});
 

    所有使用这种方式创建的类会继承extend方法,所以我们可以简单的为Animal类创建子类:
var Cat = Animal.extend({

 
  eat: function(food) {

 
    if (food instanceof Mouse) this.base();
 
    else this.say("Yuk! I only eat mice.");
 
  }
 
});
 
  
 

var Mouse = Animal.extend();
 

类属性和方法

    类里面传递给extend方法的第二个参数定义了类接口(类似java的Static方法):

var Circle = Shape.extend({ // instance interface

 
  constructor: function(x, y, radius) {

 
    this.base(x, y);
 
    this.radius = radius;
 
  },
 
  
 
  radius: 0,
 
  
 
  getCircumference: function() {

 
    return 2 * Circle.PI * this.radius;
 
  }
 
}, { // class interface

 
  PI: 3.14
 
})
 

注意构造器中的base方法的用法,它确保了Shape的构造器同样被调用。其他需要注意的地方
  • 如果你定义了一个叫做init的类方法 (不是实例方法) ,它会在类创建的时候自动的调用。
  • 在原型构造阶段(衍生子类)构造函数永远不会被调用
含有私有数据的类

    某些开发人员喜欢创建类的时候,方法在类里访问私有数据:

  1. function
  2. this.getCircumference = function() {
  3. return
  4.   };
  5. };
  6. You can achieve the same result using the Base class:
  7. var
  8. function(radius) {
  9. this.extend({
  10. function() {
  11. return
  12.       }
  13.     });
  14.   }
  15. });

    这段代码在这种情况下有一些冗长,但是你可以访问base方法了,这让我感觉非常的有用。

单一的实例

我改变了很多关于这个问题的想法,但是最后我决定通过定义一个空的构造函数来允许单一实例类的创建:

var Math = Base.extend({

 
  constructor: null,
 
  PI: 3.14,
 
  sqr: function(number) {

 
    return number * number;
 
  }
 
})
 

结论

    这个用来取代我旧OO框架----不是我曾经想要的跨浏览器的框架(并且还有其他缺点)。

    我有一个开发空间,在那里我一直在基于这个机制开发一些零碎的东西。

    你可以从这里获得Base类: Base.js.