正当我们感概万分时,天空中一道红光闪过,祥云中出现了观音菩萨。只见她手持玉净瓶,轻拂翠柳枝,洒下几滴甘露,顿时让JavaScript又添新的灵气。
观音洒下的甘露在JavaScript的世界里凝结成块,成为了一种称为“语法甘露”的东西。这种语法甘露可以让我们编写的代码看起来更象对象语言。
要想知道这“语法甘露”为何物,就请君侧耳细听。
在理解这些语法甘露之前,我们需要重新再回顾一下JavaScript构造对象的过程。
我们已经知道,用 var anObject = new aFunction() 形式创建对象的过程实际上可以分为三步:第一步是建立一个新对象;第二步将该对象内置的原型对象设置为构造函数prototype引用的那个原型对象;第三步就是将该对象作为this参数调用构造函数,完成成员设置等初始化工作。对象建立之后,对象上的任何访问和操作都只与对象自身及其原型链上的那串对象有关,与构造函数再扯不上关系了。换句话说,构造函数只是在创建对象时起到介绍原型对象和初始化对象两个作用。
那么,我们能否自己定义一个对象来当作原型,并在这个原型上描述类,然后将这个原型设置给新创建的对象,将其当作对象的类呢?我们又能否将这个原型中的一个方法当作构造函数,去初始化新建的对象呢?例如,我们定义这样一个原型对象:
Person 定义一个对象来作为原型类 {
Create: (name, age) 这个当构造函数 {
.name name;
.age age;
},
SayHello: () 定义方法 {
alert(""+thisfunction//
this+""""+this+""""这个JSON形式的写法多么象一个C#的类啊!既有构造函数,又有各种方法。如果可以用某种形式来创建对象,并将对象的内置的原型设置为上面这个“类”对象,不就相当于创建该类的对象了吗?[Page]
但遗憾的是,我们几乎不能访问到对象内置的原型属性!尽管有些浏览器可以访问到对象的内置原型,但这样做的话就只能限定了用户必须使用那种浏览器。这也几乎不可行。
那么,我们可不可以通过一个函数对象来做媒介,利用该函数对象的prototype属性来中转这个原型,并用new操作符传递给新建的对象呢?
其实,象这样的代码就可以实现这一目标:
anyfunc(){}; 定义一个函数躯壳 anyfunc.prototype Person; 将原型对象放到中转站prototype BillGates anyfunc(); 新建对象的内置原型将是我们期望的原型对象
不过,这个anyfunc函数只是一个躯壳,在使用过这个躯壳之后它就成了多余的东西了,而且这和直接使用构造函数来创建对象也没啥不同,有点不爽。
可是,如果我们将这些代码写成一个通用函数,而那个函数躯壳也就成了函数内的函数,这个内部函数不就可以在外层函数退出作用域后自动消亡吗?而且,我们可以将原型对象作为通用函数的参数,让通用函数返回创建的对象。我们需要的就是下面这个形式:
New(aClass, aParams) 通用创建函数 {
new_() 定义临时的中转函数壳 {
aClass.Create.apply(, aParams); 调用原型中定义的的构造函数,中转构造逻辑及构造参数 };
new_.prototype aClass; 准备中转原型对象 new_(); 返回建立最终建立的对象 };
Person 定义的类 {
Create: (name, age)
{
.name name;
.age age;
},
SayHello: ()
{
alert(""+thisfunctionthis+""""+this+""""var=""""53//
==//语法甘露: object 定义小写的object基本类,用于实现最基础的方法等 {
isA: (aType) 一个判断类与类之间以及对象与类之间关系的基础方法 {
self ;
(self)
{
(self aType)
;
self self.Type;
};
;
}
};
Class(aBaseClass, aClassDefine) 创建类的函数,用于声明类及继承关系 {
class_() 创建类的临时函数壳 {
.Type aBaseClass; 我们给每一个类约定一个Type属性,引用其继承的类 ( member aClassDefine)
[member] aClassDefine[member]; 复制类的全部定义到当前创建的类 };
class_.prototype aBaseClass;
class_();
};
New(aClass, aParams) 创建对象的函数,用于任意类的对象创建 {
new_() 创建对象的临时函数壳 {
.Type aClass; 我们也给每一个对象约定一个Type属性,据此可以访问到对象所属的类 (aClass.Create)
aClass.Create.apply(, aParams); 我们约定所有类的构造函数都叫Create,这和DELPHI比较相似 };
new_.prototype aClass;
new_();
};
语法甘露的应用效果: Person Class(object, 派生至object基本类 {
Create: (name, age)
{
.name name;
.age age;
},
SayHello: ()
{
alert(""+this+""""this+""""var=//
functionthis//
this=functionthis+""""+thisvar=""""53var=""""531234var=""""6//
//
false alert(SteveJobs.isA(Person)); true alert(Person.isA(Employee)); false alert(Employee.isA(Person)); true
[Page]
“语法甘露”不用太多,只要那么一点点,就能改观整个代码的易读性和流畅性,从而让代码显得更优雅。有了这些语法甘露,JavaScript就很像一般对象语言了,写起代码了感觉也就爽多了!
令人高兴的是,受这些甘露滋养的JavaScript程序效率会更高。因为其原型对象里既没有了毫无用处的那些对象级的成员,而且还不存在constructor属性体,少了与构造函数间的牵连,但依旧保持了方法的共享性。这让JavaScript在追溯原型链和搜索属性及方法时,少费许多工夫啊。
我们就把这种形式称为“甘露模型”吧!其实,这种“甘露模型”的原型用法才是符合prototype概念的本意,才是的JavaScript原型的真谛!
想必微软那些设计AJAX架构的工程师看到这个甘露模型时,肯定后悔没有早点把AJAX部门从美国搬到咱中国的观音庙来,错过了观音菩萨的点化。当然,我们也只能是在代码的示例中,把Bill Gates当作对象玩玩,真要让他放弃上帝转而皈依我佛肯定是不容易的,机缘未到啊!如果哪天你在微软新出的AJAX类库中看到这种甘露模型,那才是真正的缘分!