`

读<悟透JavaScript> 记

阅读更多

对象本无根,类型于无形,本来无一物,何处惹尘埃.....!!

 

 

原型真谛

    正当我们感概万分时,天空中一道红光闪过,祥云中出现了观音菩萨。只见她手持玉净瓶,轻拂翠柳枝,洒下几滴甘露,顿时让JavaScript又添新的灵气。

    观音洒下的甘露在JavaScript的世界里凝结成块,成为了一种称为“语法甘露”的东西。这种语法甘露可以让我们编写的代码看起来更象对象语言。

    要想知道这“语法甘露”为何物,就请君侧耳细听。

    在理解这些语法甘露之前,我们需要重新再回顾一下JavaScript构造对象的过程。

    我们已经知道,用 var anObject = new aFunction() 形式创建对象的过程实际上可以分为三步:第一步是建立一个新对象;第二步将该对象内置的原型对象设置为构造函数prototype引用的那个原型对象;第 三步就是将该对象作为this参数调用构造函数,完成成员设置等初始化工作。对象建立之后,对象上的任何访问和操作都只与对象自身及其原型链上的那串对象 有关,与构造函数再扯不上关系了。换句话说,构造函数只是在创建对象时起到介绍原型对象和初始化对象两个作用。

    那么,我们能否自己定义一个对象来当作原型,并在这个原型上描述类,然后将这个原型设置给新创建的对象,将其当作对象的类呢?我们又能否将这个原型中的一个方法当作构造函数,去初始化新建的对象呢?例如,我们定义这样一个原型对象:

     var  Person  =    // 定义一个对象来作为原型类
    {
        Create: 
function (name, age)   // 这个当构造函数
        {
            
this .name  =  name;
            
this .age  =  age;
        },
        SayHello: 
function ()   // 定义方法
        {
            alert(
" Hello, I'm  "   +   this .name);
        },
        HowOld: 
function ()   // 定义方法
        {
            alert(
this .name  +   "  is  "   +   this .age  +   "  years old. " );
        }
    };

    这个JSON形式的写法多么象一个C#的类啊!既有构造函数,又有各种方法。如果可以用某种形式来创建对象,并将对象的内置的原型设置为上面这个“类”对象,不就相当于创建该类的对象了吗?

    但遗憾的是,我们几乎不能访问到对象内置的原型属性!尽管有些浏览器可以访问到对象的内置原型,但这样做的话就只能限定了用户必须使用那种浏览器。这也几乎不可行。

    那么,我们可不可以通过一个函数对象来做媒介,利用该函数对象的prototype属性来中转这个原型,并用new操作符传递给新建的对象呢?

    其实,象这样的代码就可以实现这一目标:

     function  anyfunc(){};            // 定义一个函数躯壳
    anyfunc.prototype  =  Person;      // 将原型对象放到中转站prototype
     var  BillGates  =   new  anyfunc();   // 新建对象的内置原型将是我们期望的原型对象

    不过,这个anyfunc函数只是一个躯壳,在使用过这个躯壳之后它就成了多余的东西了,而且这和直接使用构造函数来创建对象也没啥不同,有点不爽。

    可是,如果我们将这些代码写成一个通用函数,而那个函数躯壳也就成了函数内的函数,这个内部函数不就可以在外层函数退出作用域后自动消亡吗?而且,我们可以将原型对象作为通用函数的参数,让通用函数返回创建的对象。我们需要的就是下面这个形式:

     function  New(aClass, aParams)     // 通用创建函数
    {
        
function  new_()      // 定义临时的中转函数壳
        {
            aClass.Create.apply(
this , aParams);    // 调用原型中定义的的构造函数,中转构造逻辑及构造参数
        };
        new_.prototype 
=  aClass;     // 准备中转原型对象
         return   new  new_();           // 返回建立最终建立的对象
    };
    
    
var  Person  =          // 定义的类
    {
        Create: 
function (name, age)
        {
            
this .name  =  name;
            
this .age  =  age;
        },
        SayHello: 
function ()
        {
            alert(
" Hello, I'm  "   +   this .name);
        },
        HowOld: 
function ()
        {
            alert(
this .name  +   "  is  "   +   this .age  +   "  years old. " );
        }
    };
    
    
var  BillGates  =  New(Person, [ " Bill Gates " 53 ]);   // 调用通用函数创建对象,并以数组形式传递构造参数
    BillGates.SayHello();
    BillGates.HowOld();

    alert(BillGates.constructor 
==  Object);      // 输出:true

    这里的通用函数New()就是一个“语法甘露”!这个语法甘露不但中转了原型对象,还中转了构造函数逻辑及构造参数。

    有趣的是,每次创建完对象退出New函数作用域时,临时的new_函数对象会被自动释放。由于new_的prototype属性被设置为新的原型 对象,其原来的原型对象和new_之间就已解开了引用链,临时函数及其原来的原型对象都会被正确回收了。上面代码的最后一句证明,新创建的对象的 constructor属性返回的是Object函数。其实新建的对象自己及其原型里没有constructor属性,那返回的只是最顶层原型对象的构造 函数,即Object。

    有了New这个语法甘露,类的定义就很像C#那些静态对象语言的形式了,这样的代码显得多么文静而优雅啊!

    当然,这个代码仅仅展示了“语法甘露”的概念。我们还需要多一些的语法甘露,才能实现用简洁而优雅的代码书写类层次及其继承关系。好了,我们再来看一个更丰富的示例吧:

     // 语法甘露:
     var  object  =      // 定义小写的object基本类,用于实现最基础的方法等
    {
        isA: 
function (aType)    // 一个判断类与类之间以及对象与类之间关系的基础方法
        {
            
var  self  =   this ;
            
while (self)
            {
                
if  (self  ==  aType)
                  
return   true ;
                self 
=  self.Type;
            };
            
return   false ;
        }
    };
    
    
function  Class(aBaseClass, aClassDefine)     // 创建类的函数,用于声明类及继承关系
    {
        
function  class_()    // 创建类的临时函数壳
        {
            
this .Type  =  aBaseClass;     // 我们给每一个类约定一个Type属性,引用其继承的类
             for ( var  member  in  aClassDefine)
                
this [member]  =  aClassDefine[member];     // 复制类的全部定义到当前创建的类
        };
        class_.prototype 
=  aBaseClass;
        
return   new  class_();
    };
    
    
function  New(aClass, aParams)    // 创建对象的函数,用于任意类的对象创建
    {
        
function  new_()      // 创建对象的临时函数壳
        {
            
this .Type  =  aClass;     // 我们也给每一个对象约定一个Type属性,据此可以访问到对象所属的类
             if  (aClass.Create)
              aClass.Create.apply(
this , aParams);    // 我们约定所有类的构造函数都叫Create,这和DELPHI比较相似
        };
        new_.prototype 
=  aClass;
        
return   new  new_();
    };

    
// 语法甘露的应用效果:    
     var  Person  =  Class(object,       // 派生至object基本类
    {
        Create: 
function (name, age)
        {
            
this .name  =  name;
            
this .age  =  age;
        },
        SayHello: 
function ()
        {
            alert(
" Hello, I'm  "   +   this .name  +   " "   +   this .age  +   "  years old. " );
        }
    });
    
    
var  Employee  =  Class(Person,     // 派生至Person类,是不是和一般对象语言很相似?
    {
        Create: 
function (name, age, salary)
        {
            Person.Create.call(
this , name, age);   // 调用基类的构造函数
             this .salary  =  salary;
        },
        ShowMeTheMoney: 
function ()
        {
            alert(
this .name  +   "  $ "   +   this .salary);
        }
    });

    
var  BillGates  =  New(Person, [ " Bill Gates " 53 ]);
    
var  SteveJobs  =  New(Employee, [ " Steve Jobs " 53 1234 ]);
    BillGates.SayHello();
    SteveJobs.SayHello();
    SteveJobs.ShowMeTheMoney();
    
    
var  LittleBill  =  New(BillGates.Type, [ " Little Bill " 6 ]);    // 根据BillGate的类型创建LittleBill
    LittleBill.SayHello();
    
    alert(BillGates.isA(Person));       
// true
    alert(BillGates.isA(Employee));      // false
    alert(SteveJobs.isA(Person));        // true
    alert(Person.isA(Employee));         // false
    alert(Employee.isA(Person));         // true

    “语法甘露”不用太多,只要那么一点点,就能改观整个代码的易读性和流畅性,从而让代码显得更优雅。有了这些语法甘露,JavaScript就很像一般对象语言了,写起代码了感觉也就爽多了!

    令人高兴的是,受这些甘露滋养的JavaScript程序效率会更高。因为其原型对象里既没有了毫无用处的那些对象级的成员,而且还不存在 constructor属性体,少了与构造函数间的牵连,但依旧保持了方法的共享性。这让JavaScript在追溯原型链和搜索属性及方法时,少费许多 工夫啊。

    我们就把这种形式称为“甘露模型”吧!其实,这种“甘露模型”的原型用法才是符合prototype概念的本意,才是的JavaScript原型的真谛!

    想必微软那些设计AJAX架构的工程师看到这个甘露模型时,肯定后悔没有早点把AJAX部门从美国搬到咱中国的观音庙来,错过了观音菩萨的点化。 当然,我们也只能是在代码的示例中,把Bill Gates当作对象玩玩,真要让他放弃上帝转而皈依我佛肯定是不容易的,机缘未到啊!如果哪天你在微软新出的AJAX类库中看到这种甘露模型,那才是真正 的缘分!

 

分享到:
评论

相关推荐

    网页教程代码参考

    &lt;br&gt;HTML&lt;br&gt;HTML教程&lt;br&gt;&lt;br&gt;HTML代码示例&lt;br&gt;&lt;br&gt;HTML参考(Reference)&lt;br&gt;&lt;br&gt;HTML知识库&lt;br&gt;&lt;br&gt;CSS&lt;br&gt;CSS教程&lt;br&gt;&lt;br&gt;CSS代码示例&lt;br&gt;&lt;br&gt;CSS参考(Reference)&lt;br&gt;&lt;br&gt;Javascript&lt;br&gt;Javascript教程&lt;br&gt;&lt;br&gt;...

    javascrip上百技术总集

    初看原型&lt;br&gt;悟透JavaScript(李站老师)-对象素描&lt;br&gt;悟透JavaScript(李站老师)-放下对象&lt;br&gt;悟透JavaScript(李站老师)-构造对象&lt;br&gt;悟透JavaScript(李站老师)-原型扩展&lt;br&gt;用javascript操作 asp .net ...

    悟透JavaScript.rar

    "悟透JavaScript"这个压缩包文件显然是一份旨在帮助学习者深入理解这门语言的教程资料。从标签"书籍教程-网页制作"我们可以推测,这份教程可能包含了JavaScript在网页制作中的实际应用和相关理论知识。 "悟透...

    Vue中通过<script></script>引入的Vue.js文件

    &lt;script src="./js/vue%20(1).js" type="text/javascript" charset="UTF-8"&gt;&lt;/script&gt; src里面的内容根据自己的下载的Vue.js的文件位置决定的,我这里只是拿我自己做的举个例子。这个地方的vue.js是因为我下载了两次...

    悟透JavaScript

    资源名称:悟透Javascript内容简介:翻开此书的你,也许是Javascript的崇拜者,正想摩拳擦掌地想尝试下学一学这一精巧的语言;也许是80后,90后的程序员或者前端架构师,正被Javascript魔幻般的...

    悟透JavaScript.pdf

    ### 悟透JavaScript核心知识点解析 #### 一、编程世界的本质:数据与代码 **悟透JavaScript**这本书深入探讨了编程世界的核心——数据与代码之间的关系。在编程的世界里,一切皆可归结为这两种基本元素:数据与...

    JavaScript for breakfast Crunching scripts for your coffee table (含源代码)

    &lt;br&gt;JavaScript for breakfast Crunching scripts for your coffee table&lt;br&gt;&lt;br&gt;包含源代码&lt;br&gt;&lt;br&gt;&lt;br&gt;Tom Dell\'Aringa &lt;br&gt;&lt;br&gt;Published by DMXzone.com &lt;br&gt;&lt;br&gt;Dynamic Zones International &lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;...

    悟透javascript.pdf

    - 关系运算符:`&gt;`、`&lt;`、`&gt;=`、`&lt;=`、`==`、`!=`、`===`、`!==`等。 - 逻辑运算符:`&&`(与)、`||`(或)、`!`(非)等。 - 赋值运算符:`=`、`+=`、`-=`等。 3. **控制结构**: - 条件语句:`if`、`else if...

    北大青鸟第一学期4.0 S1所有资料一

    我已经把第一学期所有的课件打包在一起了,一共有5部分,这是第一部分&lt;br&gt;&lt;br&gt;大家载时要记得评分,这样你们就不要资源分了&lt;br&gt;&lt;br&gt;C语言&lt;br&gt;&lt;br&gt;HTML && JavaScript 电子档课件ppt.rar&lt;br&gt;&lt;br&gt;java&&OOP &lt;br&gt;&lt;br&gt;SQL...

    javascript网页特效108个

    javascript网页特效108个&lt;br&gt;http://bbs.esiyang.com收集的.&lt;br&gt;Javascript 3D相册 &lt;br&gt;图片轮换效果总结 &lt;br&gt;Javascript 3D相册 &lt;br&gt;多样化摺叠菜单 &lt;br&gt;一个很酷的登陆效果! &lt;br&gt;WINDOWS脚本技术大全 &lt;br&gt;新浪...

    轻轻松松学用javascript编程(PDF)

    - 属性和方法&lt;br&gt;2.2 JavaScript 代码的加入 &lt;br&gt;2.2.1 加入JavaScript 代码的方式一&lt;br&gt;2.2.2 加入JavaScript 代码的方式二&lt;br&gt;2.2.3 加入JavaScript 代码的方式三&lt;br&gt;3 JavaScript 常用对象的例子&lt;br&gt;3.1 一个最...

    Javascript基础网页中调用JS代码的几种方法

    &lt;script src="script.js" language="javascript"&gt;&lt;/script&gt; &lt;/head&gt; &lt;body&gt; &lt;button onclick="showMessage()"&gt;显示消息&lt;/button&gt; &lt;/body&gt; &lt;/html&gt; ``` 其中,“script.js”是外部JavaScript文件的路径。 #### 3. ...

    菜鸟学习javascript实例教程.pdf

    关于JavaScript的位置,它可以在`&lt;head&gt;`或`&lt;body&gt;`标签中编写,但通常建议将其放在`&lt;body&gt;`的底部,以确保在页面加载时脚本不会阻塞内容的呈现。如果希望在页面加载时执行某个功能,可以使用`onload`事件,如下所示...

    java代码的基础引入方法

    在上面的例子中,我们直接在`&lt;body&gt;`标签内部使用`&lt;script&gt;`标签来插入JavaScript代码。这种方式适合少量的JavaScript代码或简单的逻辑处理。 #### 外部文件引入 当JavaScript代码量较大时,建议将其存储在一个...

    dwr实现消息精确推送

    &lt;script type="text/javascript" src="&lt;%=basepath%&gt;dwr/interface/MessagePush.js"&gt;&lt;/script&gt; ``` 其中,`engine.js`和`util.js`是DWR提供的基础库文件,而`MessagePush.js`则是在`dwr.xml`中定义的接口文件。 ##...

    悟透javascript

    《悟透JavaScript:回归数据与代码的本原》 在《悟透JavaScript》一书中,作者李战(leadzen)引领读者深入理解JavaScript的核心概念,强调了编程世界中数据与代码的基本关系及其在JavaScript中的独特体现。本书...

Global site tag (gtag.js) - Google Analytics