对于 JavaScript,我是既爱又头疼。喜欢它的简洁和灵活性,头疼那 "面向过程" 的开发方式。也正因为如此,我曾在相当长的时间里拒绝使用它。对于一个习惯了 OO 思想的人来说,将数据和行为分离的编码风格纯粹是一种痛苦折磨。混乱的 HTML 加上同样乱糟糟的 .js,让我无时无刻不觉得那是一块沼泽地。兴许是完美主义洁癖在作怪,new function、对象冒充、原型链,亦或者李战大侠的 "甘露模型" 都不太符合我的要求。面向对象并不仅仅是对象和继承,它还包括更多的东西。总算是功夫不负有心人,JS.Class —— Ruby-like classes for JavaScript 几乎完美地做到了这些,同时也让我见识了 JavaScript 的强大。
JS.Class 库被设计用来简化 JavaScript 面向对象开发,它借鉴了 Ruby 的几种风格来模拟 Classes、Inheritance、Mixins 以及 Modules。(尽管作者在介绍里使用 "simulate" 这个词,但我觉得这更像是 DSL 的一种)
首先我们看一个简单的演示。
var User = new JS.Class(
{
initialize : function(name)
{
if (name != undefined) this.name = name;
},
name : "Anonymous",
age : 0,
sex : "UnKnown",
getInfo : function()
{
return "Name: " + this.name + "; Age: " + this.age + "; Sex: " + this.sex;
},
show : function(content)
{
alert("<User>\r\n" + content);
}
});
var user = new User("Tom");
user.age = 30;
user.sex = "Female";
var info = user.getInfo();
user.show(info);
嗯~~~ 这应该说是创建一个类对象,而非类定义。JSON 方式看上去简洁美观,JS.Class 接收一个定义对象来完成 Class 定义。initialize 可以理解为实例初始化方法 (.ctor),它包含了构造一个对象所需的参数/属性。调用代码完全类似 C#/Java 风格,熟悉的 new 关键字以及成员调用。
创建一个继承子类同样很简单。
var Manager = new JS.Class(User,
{
initialize : function(name, address)
{
this.callSuper();
this.address = address;
},
address : "UnKnown",
test : function()
{
alert(this.name);
},
show : function(content)
{
content += " (Manager)";
this.callSuper(content);
}
});
var user = new Manager("Tom");
user.age = 30;
user.sex = "Female";
var info = user.getInfo();
user.show(info);
JS.Class 通过接收基类对象和新增成员对象两个参数来创建子类。除了新增成员外,我们还可以 override 基类的方法。这里面出现了一个 callSuper() 方法,作用类似 C# 里面的 base,它可以自动处理方法参数并调用基类方法。不过需要注意的是,如果我们修改了参数,那么必须显式添加调用参数。
看看不显示添加调用参数的结果。
show : function(content)
{
content += " (Manager)";
this.callSuper();
}
输出:
<User>
Name: Tom; Age: 30; Sex: Female
子类的初始化方法不是必须的,但如果需要,同样可以重写。
JS.Class 还允许我们创建静态方法 (static method),这是其他 JavaScript OO 模型所没有的。
var User = new JS.Class(
{
initialize: function(name)
{
this.name = name;
},
extend:
{
getInfo: function(user)
{
return user.name;
},
show: function(s)
{
alert(s);
}
}
});
var Manager = new JS.Class(User,
{
initialize : function(name, age)
{
this.callSuper(name);
this.age = age;
},
extend:
{
getInfo : function(user)
{
return this.callSuper() + ";" + user.age;
}
}
});
var manager = new Manager("Tom", 31);
var info = Manager.getInfo(manager);
Manager.show(info);
使用 extend 包含所有的静态成员,子类会自动继承基类的静态方法,并可以改写。静态方法使用类变量调用而非实例变量,这也是我们所熟悉的。