首先声明:prototype !=
Prototype。前者是指 JavaScript 中用来实现继承的东东,后者是大名鼎鼎的 JavaScript 可重用基础库。
JavaScript 让人又爱又恨。爱的是她使用起来非常方便,三两个语句就可以实现一个用户交互操作。恨的是她太过灵活,又没有标准的类库,以致于在大型的项目中使用和维护起来非常困难。
相信很多人初学 JavaScript 的人都领教过 prototype 的晦涩,特别是对于有过其它面向对象编程语言使用经验的程序员来说,prototype 的继承机制大大地限制了他们设计技巧。
一种编程语言决定一种思维方式。同一个模型如果用 C 语言来实现,你只会小心翼翼地把玩内存块和指针;如果用 java 来实现,你可以轻轻松松地使用类来描绘这个模型中的各个实物。
在 JavaScript 中,你想创建一个新类,并继承一个现有的类。你必须首先生成父类的一个实例,然后将这个实例设为子类构造函数的 prototype。这是一种奇怪的思维方式,我明明在设计类,怎么我必须创建实例呢?在这个实例的创建过程中会不会发生我意想不到的事情呢?
很多人试图避开这个奇怪的语法,我也是其中之一。方法无非就是编写一个函数来封装这个继承过程。这样的方法有很多,本人觉得比较好的是 json 作者在文章
《Classical Inheritance in JavaScript》 中提到的 inherits 方法。
我的想法是,干脆不用 prototype,使用现有的语言设施类模拟整个构造实例的过程,从而实现真正意义上的继承,甚至多继承,接口等等。
Modello 就是基于这种思想写出来的。
Modello 不仅在功能上实现了完整的面向对象支持,还从美学角度上加以考虑。如果是找女朋友,首先要考虑漂亮,然后再考虑简单;如果是选择编程语言,则要反过来(仅代表个人观点)。因为程序是由人写,给人看的。简单的语法,学起来容易上手,写起来效率高,看起来易懂,所谓“望文生义”;优美的语法可以给写程序和读程序的人带来乐趣和美感。
除此之外,和现有标准、现有工具兼容也是很重要的。
Modello 兼容用 prototype 方式编写的类,兼容用
Prototype 方式编写的类。
好了,下面通过例子来说明:
// 创建一个类
// 兼容 Prototype 的语法
var C1 = Class.create();
// 单继承
var C2 = Class.create(C1);
// 多继承
var C4 = Class.create(C1, C2);
// 设计类
C4.construct = function ($self, $class) {
// 用 var 关键字来声明私有属性
var _age = '';
// 用 this 关键字来声明公有属性
this.name = '';
// 声明初始化函数
this.initialize = function () {
// 使用 $self.superN 来访问父类公有属性
$self.super0.initialize.call(this); // 调用 C1 的初始化函数
$self.super1.initialize.call(this); // 调用 C2 的初始化函数
}
}
// 创建实例
var obj = new C4;
下面来个复杂一点的例子,该例子改写自
Atlas 的
Interface 例子。
// IPet 接口
var IPet = Class.create();
IPet.construct = function() {
this.returnFriendlyName = Class.abstractMethod;
}
// Animal 类
var Animal = Class.create();
Animal.construct = function() {
var _name;
this.initialize = function(name) {
_name = name;
}
this.returnName = function() {
return _name;
}
this.toStringCustom = function() {
return this.returnName();
}
this.speak = Class.abstractMethod;
}
// Pet 类,继承自 Animal,实现 IPet
var Pet = Class.create(Animal, IPet);
Pet.construct = function($self) {
var _friendlyName;
this.initialize = function(name, friendlyName) {
$self.super0.initialize.call(this, name);
_friendlyName = friendlyName;
}
this.returnFriendlyName = function() {
return _friendlyName;
}
}
// Cat 类,继承自 Pet
var Cat = Class.create(Pet);
Cat.construct = function($self) {
this.initialize = function(friendlyName) {
$self.super0.initialize.call(this, 'Cat', friendlyName);
}
this.speak = function() {
alert('meow');
}
this.toStringCustom = function() {
return 'Pet ' + $self.super0.toStringCustom.call(this);
}
}
// Felix 类,继承自 Cat
var Felix = Class.create(Cat);
Felix.construct = function($self) {
this.initialize = function() {
$self.super0.initialize.call(this, 'Felix');
}
this.toStringCustom = function() {
return $self.super0.toStringCustom.call(this) + ' ... its Felix!';
}
}
// Dog 类,继承自 Pet
var Dog = Class.create(Pet);
Dog.construct = function($self) {
this.initialize = function(friendlyName) {
$self.super0.initialize.call(this, 'Dog', friendlyName);
}
this.speak = function() {
alert('woof');
}
}
// Tiger 类,继承自 Animal
var Tiger = Class.create(Animal);
Tiger.construct = function($self) {
this.initialize = function() {
$self.super0.initialize.call(this, 'Tiger');
}
this.speak = function() {
alert('grrr');
}
}
运行这个例子:
Modello Example: Interface
关于
Modello,
这里有更详细的介绍。
Modello 的原意为“大型艺术作品的模型”,希望
Modello 能够帮助你编写高质量的 JavaScript 代码。