忘记 prototype,使用 Modello 来编写 JavaScript 类

来源:互联网 发布:网络信用贷款 编辑:程序博客网 时间:2024/04/29 12:25
首先声明: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 代码。
原创粉丝点击