<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<?xml-stylesheet type="text/xsl" href="css/rss.xslt"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>张三的部落格</title><link>http://www.zhangsan.net/</link><description>http://www.zhangsan.net/</description><generator>RainbowSoft Studio Z-Blog 1.8 Spirit Build 80605</generator><language>zh-CN</language><copyright>Copyright 2005-2008 zhangsan.net. Some Rights Reserved.</copyright><pubDate>Wed, 10 Dec 2008 15:02:52 +0800</pubDate><item><title>IE7,6与Fireofx的CSS兼容性处理方法大全</title><author>a@b.com (liangshan)</author><link>http://www.zhangsan.net/post/123.html</link><pubDate>Wed, 10 Dec 2008 15:01:45 +0800</pubDate><guid>http://www.zhangsan.net/post/123.html</guid><description><![CDATA[<p>从网上收集了IE7,6与Fireofx的兼容性处理方法并整理了一下.对于web2.0的过度,请尽量用xhtml格式写代码,而且DOCTYPE 影响 CSS 处理,作为W3C的标准,一定要加 DOCTYPE声名. <br /><br />CSS技巧<br /><br />1.div的垂直居中问题 vertical-align:middle; 将行距增加到和整个DIV一样高 line-height:200px; 然后插入文字，就垂直居中了。缺点是要控制内容不要换行 <br /><br />2. margin加倍的问题 设置为float的div在ie下设置的margin会加倍。这是一个ie6都存在的bug。解决方案是在这个div里面加上 display:inline; 例如： &lt;#div id=&rdquo;imfloat&rdquo;&gt; 相应的css为 #IamFloat{ float:left; margin:5px; /*IE下理解为10px*/ display:inline;/*IE下再理解为5px*/} <br /><br />3.浮动ie产生的双倍距离 #box{ float:left; width:100px; margin:0 0 0 100px; //这种情况之下IE会产生200px的距离 display:inline; //使浮动忽略} 这里细说一下block与inline两个元素：block元素的特点是,总是在新行上开始,高度,宽度,行高,边距都可以控制 (块元素);Inline元素的特点是,和其他元素在同一行上,不可控制(内嵌元素); #box{ display:block; //可以为内嵌元素模拟为块元素 display:inline; //实现同一行排列的效果 diplay:table; <br /><br />4 IE与宽度和高度的问题 IE 不认得min-这个定义，但实际上它把正常的width和height当作有min的情况来使。这样问题就大了，如果只用宽度和高度，正常的浏览器里这两个值就不会变，如果只用min-width和min-height的话，IE下面根本等于没有设置宽度和高度。 比如要设置背景图片，这个宽度是比较重要的。要解决这个问题，可以这样： #box{ width: 80px; height: 35px;}html&gt;body #box{ width: auto; height: auto; min-width: 80px; min-height: 35px;} <br /><br />5. 页面的最小宽度 min -width是个非常方便的CSS命令，它可以指定元素最小也不能小于某个宽度，这样就能保证排版一直正确。但IE不认得这个，而它实际上把width当做最小宽度来使。为了让这一命令在IE上也能用，可以把一个&lt;div&gt; 放到 &lt;body&gt; 标签下，然后为div指定一个类, 然后CSS这样设计： #container{ min-width: 600px; width:e-xpression(document.body.clientWidth &lt; 600? &quot;600px&quot;: &quot;auto&quot; );} 第一个min-width是正常的；但第2行的width使用了Javascript，这只有IE才认得，这也会让你的HTML文档不太正规。它实际上通过Javascript的判断来实现最小宽度。<br /><br />6.DIV浮动IE文本产生3象素的bug 左边对象浮动，右边采用外补丁的左边距来定位，右边对象内的文本会离左边有3px的间距. #box{ float:left; width:800px;} #left{ float:left; width:50%;} #right{ width:50%;} *html #left{ margin-right:-3px; //这句是关键} &lt;div id=&quot;box&quot;&gt; &lt;div id=&quot;left&quot;&gt;&lt;/div&gt; &lt;div id=&quot;right&quot;&gt;&lt;/div&gt; &lt;/div&gt; <br /><br />7.IE捉迷藏的问题 当div应用复杂的时候每个栏中又有一些链接，DIV等这个时候容易发生捉迷藏的问题。 有些内容显示不出来，当鼠标选择这个区域是发现内容确实在页面。 解决办法：对#layout使用line-height属性或者给#layout使用固定高和宽。页面结构尽量简单。 <br /><br />8.float的div闭合;清除浮动;自适应高度; <br /><br />① 例如：&lt;#div id=&rdquo;floatA&rdquo; &gt;&lt;#div id=&rdquo;floatB&rdquo; &gt;&lt;#div id=&rdquo; NOTfloatC&rdquo; &gt;这里的NOTfloatC并不希望继续平移，而是希望往下排。(其中floatA、floatB的属性已经设置为 float:left;) 这段代码在IE中毫无问题，问题出在FF。原因是NOTfloatC并非float标签，必须将float标签闭合。在 &lt;#div class=&rdquo;floatB&rdquo;&gt; &lt;#div class=&rdquo;NOTfloatC&rdquo;&gt;之间加上 &lt; #div class=&rdquo;clear&rdquo;&gt;这个div一定要注意位置，而且必须与两个具有float属性的div同级，之间不能存在嵌套关系，否则会产生异常。并且将clear这种样式定义为为如下即可： .clear{ clear:both;} <br /><br />②作为外部 wrapper 的 div 不要定死高度,为了让高度能自动适应，要在wrapper里面加上overflow:hidden; 当包含float的 box的时候，高度自动适应在IE下无效，这时候应该触发IE的layout私有属性(万恶的IE啊！)用zoom:1;可以做到，这样就达到了兼容。 例如某一个wrapper如下定义： .colwrapper{ overflow:hidden; zoom:1; margin:5px auto;} <br /><br />③对于排版,我们用得最多的css描述可能就是float:left.有的时候我们需要在n 栏的float div后面做一个统一的背景,譬如: &lt;div id=&rdquo;page&rdquo;&gt; &lt;div id=&rdquo;left&rdquo;&gt;&lt;/div&gt; &lt;div id=&rdquo;center&rdquo;&gt;&lt;/div&gt; &lt;div id=&rdquo;right&rdquo;&gt;&lt;/div&gt; &lt;/div&gt; 比如我们要将page的背景设置成蓝色,以达到所有三栏的背景颜色是蓝色的目的,但是我们会发现随着left center right的向下拉长,而 page居然保存高度不变,问题来了,原因在于page不是float属性,而我们的page由于要居中,不能设置成float,所以我们应该这样解决 &lt;div id=&rdquo;page&rdquo;&gt; &lt;div id=&rdquo;bg&rdquo; style=&rdquo;float:left;width:100%&rdquo;&gt; &lt;div id=&rdquo;left&rdquo;&gt;&lt;/div&gt; &lt;div id=&rdquo;center&rdquo;&gt;&lt;/div&gt; &lt;div id=&rdquo;right&rdquo;&gt;&lt;/div&gt; &lt;/div&gt; &lt;/div&gt; 再嵌入一个float left而宽度是100%的DIV解决之</p>]]></description><category>文摘随笔</category><comments>http://www.zhangsan.net/post/123.html#comment</comments><wfw:comment>http://www.zhangsan.net/</wfw:comment><wfw:commentRss>http://www.zhangsan.net/feed.asp?cmt=123</wfw:commentRss><trackback:ping>http://www.zhangsan.net/cmd.asp?act=tb&amp;id=123&amp;key=a4390075</trackback:ping></item><item><title>谁是强盗？微软“黑屏”有错吗？</title><author>a@b.com (liangshan)</author><link>http://www.zhangsan.net/post/121.html</link><pubDate>Tue, 21 Oct 2008 07:14:23 +0800</pubDate><guid>http://www.zhangsan.net/post/121.html</guid><description><![CDATA[<p>今天铺天盖地的关于微软&ldquo;黑屏&rdquo;的消息充斥了几乎所有的媒体。作为泱泱大国的国民居然有80%以上的受访者和众多的媒体对微软进行了炮轰。说他们没有权利这样做，说他们侵犯了消费者的权利，说他们是垄断，说他们怎么怎么样！把微软说成了一个全面公敌。</p><p>然而我在反思，就&ldquo;黑屏&rdquo;一事来说，微软真的就那么十恶不赦吗？</p><p>首先，我来说说&ldquo;黑屏&rdquo;，此次的正版验证并没有将客户的电脑完全锁定，而只是将用户的桌面设置成黑色，并提示你这是盗版的。另外office系统将出现盗版标记。我觉得在软件行业做这样的验证是很正常的，君不见多少大型、小型的软件都存在这样的验证方式，就是先从客户端提取信息然后到网上验证，验证不通过就不能使用，或者出现试用版水印，对比之下，微软还做晚了呢！</p><p>再说了，微软做正版验证也是为了维护自己的合法权益呀！好多人都说微软已经挣了足够的钱，而且微软的os卖的很贵，可我觉得那是人家的事，人家愿意卖多少就多少，人家挣了多少也是人家的事，你们不用看着不平衡。反而是我们盗用了人家的东西，反而还责怪人家来讨账。到底谁是强盗呢！&nbsp;</p><p>再说说&ldquo;版权保护&rdquo;，我也是个准程序员吧，知道软件开发的艰辛，国内的软件开发者都清楚，一般意义的软件在中国只能被破解、盗版，根本不用想赚钱。在著名的csdn上有大量的关于版权保护的帖子，其中有人说道，如果你的软件还算好用的话，第一天发布，第二天肯定出注册机。这就是中国版权保护的现状，至于和其他国家的对比，在此不必赘述，有不相信的可以参看《程序员》杂志。</p><p>我们偷了人家的东西，反而责怪人家来讨债，这不是强盗是什么？！</p>]]></description><category>文摘随笔</category><comments>http://www.zhangsan.net/post/121.html#comment</comments><wfw:comment>http://www.zhangsan.net/</wfw:comment><wfw:commentRss>http://www.zhangsan.net/feed.asp?cmt=121</wfw:commentRss><trackback:ping>http://www.zhangsan.net/cmd.asp?act=tb&amp;id=121&amp;key=4167e5b6</trackback:ping></item><item><title>Flash游戏：Bloxorz另类推箱子</title><author>a@b.com (liangshan)</author><link>http://www.zhangsan.net/post/120.html</link><pubDate>Mon, 13 Oct 2008 12:03:17 +0800</pubDate><guid>http://www.zhangsan.net/post/120.html</guid><description><![CDATA[<p>很有意思的小游戏</p><p>游戏说明：就是把这个长方块最后给挪到那个窟窿里去，只要不掉下去就行</p><p><embed menu="true" loop="true" play="true" type="application/x-shockwave-flash" src="http://img2.pconline.com.cn/pconline/0708/28/1091170_28turningsqure.swf" width="420" height="225"></embed></p><p><a target="_blank" href="http://img2.pconline.com.cn/pconline/0708/28/1091170_28turningsqure.swf">全屏游戏</a></p>]]></description><category>文摘随笔</category><comments>http://www.zhangsan.net/post/120.html#comment</comments><wfw:comment>http://www.zhangsan.net/</wfw:comment><wfw:commentRss>http://www.zhangsan.net/feed.asp?cmt=120</wfw:commentRss><trackback:ping>http://www.zhangsan.net/cmd.asp?act=tb&amp;id=120&amp;key=0fab5bce</trackback:ping></item><item><title>关于那个韩国背心男</title><author>a@b.com (liangshan)</author><link>http://www.zhangsan.net/post/119.html</link><pubDate>Mon, 13 Oct 2008 08:07:37 +0800</pubDate><guid>http://www.zhangsan.net/post/119.html</guid><description><![CDATA[<p>有一个韩国背心男通过视频列举得中国人的&ldquo;七宗罪&rdquo;，<br />视频地址：<a href="http://games.qq.com/a/20081009/000231.htm">http://games.qq.com/a/20081009/000231.htm</a></p><p>个中问题需要中国人深刻反省，而不是巧言分辨。<img alt="" src="http://www.zhangsan.net/image/face/Angry.gif" /></p>]]></description><category>文摘随笔</category><comments>http://www.zhangsan.net/post/119.html#comment</comments><wfw:comment>http://www.zhangsan.net/</wfw:comment><wfw:commentRss>http://www.zhangsan.net/feed.asp?cmt=119</wfw:commentRss><trackback:ping>http://www.zhangsan.net/cmd.asp?act=tb&amp;id=119&amp;key=862a0d1d</trackback:ping></item><item><title>[转] 悟透JavaScript</title><author>a@b.com (liangshan)</author><link>http://www.zhangsan.net/post/118.html</link><pubDate>Sat, 04 Oct 2008 17:31:14 +0800</pubDate><guid>http://www.zhangsan.net/post/118.html</guid><description><![CDATA[<p>引子<br /><br />&nbsp;&nbsp;&nbsp; 编程世界里只存在两种基本元素，一个是数据，一个是代码。编程世界就是在数据和代码千丝万缕的纠缠中呈现出无限的生机和活力。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;数据天生就是文静的，总想保持自己固有的本色；而代码却天生活泼，总想改变这个世界。<br />&nbsp;<br />&nbsp;&nbsp; 你看，数据代码间的关系与物质能量间的关系有着惊人的相似。数据也是有惯性的，如果没有代码来施加外力，她总保持自己原来的状态。而代码就象能量，他存在的唯一目的，就是要努力改变数据原来的状态。在代码改变数据的同时，也会因为数据的抗拒而反过来影响或改变代码原有的趋势。甚至在某些情况下，数据可以转变为代码，而代码却又有可能被转变为数据，或许还存在一个类似E=MC2形式的数码转换方程呢。然而，就是在数据和代码间这种即矛盾又统一的运转中，总能体现出计算机世界的规律，这些规律正是我们编写的程序逻辑。<br /><br />&nbsp;&nbsp;&nbsp; 不过，由于不同程序员有着不同的世界观，这些数据和代码看起来也就不尽相同。于是，不同世界观的程序员们运用各自的方法论，推动着编程世界的进化和发展。<br />&nbsp;<br />&nbsp;&nbsp;&nbsp; 众所周知，当今最流行的编程思想莫过于面向对象编程的思想。为什么面向对象的思想能迅速风靡编程世界呢？因为面向对象的思想首次把数据和代码结合成统一体，并以一个简单的对象概念呈现给编程者。这一下子就将原来那些杂乱的算法与子程序，以及纠缠不清的复杂数据结构，划分成清晰而有序的对象结构，从而理清了数据与代码在我们心中那团乱麻般的结。我们又可以有一个更清晰的思维，在另一个思想高度上去探索更加浩瀚的编程世界了。<br /><br />&nbsp;&nbsp;&nbsp; 在五祖弘忍讲授完《对象真经》之后的一天，他对众弟子们说：&ldquo;经已讲完，想必尔等应该有所感悟，请各自写个偈子来看&rdquo;。大弟子神秀是被大家公认为悟性最高的师兄，他的偈子写道：&ldquo;身是对象树，心如类般明。朝朝勤拂拭，莫让惹尘埃！&rdquo;。此偈一出，立即引起师兄弟们的轰动，大家都说写得太好了。只有火头僧慧能看后，轻轻地叹了口气，又随手在墙上写道：&ldquo;对象本无根，类型亦无形。本来无一物，何处惹尘埃？&rdquo;。然后摇了摇头，扬长而去。大家看了慧能的偈子都说： &ldquo;写的什么乱七八糟的啊，看不懂&rdquo;。师父弘忍看了神秀的诗偈也点头称赞，再看慧能的诗偈之后默然摇头。就在当天夜里，弘忍却悄悄把慧能叫到自己的禅房，将珍藏多年的软件真经传授于他，然后让他趁着月色连夜逃走...<br /><br />&nbsp;&nbsp;&nbsp; 后来，慧能果然不负师父厚望，在南方开创了禅宗另一个广阔的天空。而慧能当年带走的软件真经中就有一本是《JavaScript真经》！<br /><br />回归简单<br /><br />&nbsp;&nbsp;&nbsp; 要理解JavaScript，你得首先放下对象和类的概念，回到数据和代码的本原。前面说过，编程世界只有数据和代码两种基本元素，而这两种元素又有着纠缠不清的关系。JavaScript就是把数据和代码都简化到最原始的程度。<br /><br />&nbsp;&nbsp;&nbsp; JavaScript中的数据很简洁的。简单数据只有 undefined, null, boolean, number和string这五种，而复杂数据只有一种，即object。这就好比中国古典的朴素唯物思想，把世界最基本的元素归为金木水火土，其他复杂的物质都是由这五种基本元素组成。<br /><br />&nbsp;&nbsp;&nbsp; JavaScript中的代码只体现为一种形式，就是function。<br /><br />&nbsp;&nbsp;&nbsp; 注意：以上单词都是小写的，不要和Number, String, Object, Function等JavaScript内置函数混淆了。要知道，JavaScript语言是区分大小写的呀!<br /><br />&nbsp;&nbsp;&nbsp; 任何一个JavaScript的标识、常量、变量和参数都只是unfined, null, bool, number, string, object 和 function类型中的一种，也就typeof返回值表明的类型。除此之外没有其他类型了。<br /><br />&nbsp;&nbsp;&nbsp; 先说说简单数据类型吧。<br /><br />&nbsp;&nbsp;&nbsp; undefined:&nbsp;&nbsp; 代表一切未知的事物，啥都没有，无法想象，代码也就更无法去处理了。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注意：typeof(undefined) 返回也是 undefined。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 可以将undefined赋值给任何变量或属性，但并不意味了清除了该变量，反而会因此多了一个属性。<br /><br />&nbsp;&nbsp;&nbsp; null:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 有那么一个概念，但没有东西。无中似有，有中还无。虽难以想象，但已经可以用代码来处理了。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注意：typeof(null)返回object，但null并非object，具有null值的变量也并非object。<br /><br />&nbsp;&nbsp;&nbsp; boolean:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 是就是，非就非，没有疑义。对就对，错就错，绝对明确。既能被代码处理，也可以控制代码的流程。<br /><br />&nbsp;&nbsp;&nbsp; number:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 线性的事物，大小和次序分明，多而不乱。便于代码进行批量处理，也控制代码的迭代和循环等。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 注意：typeof(NaN)和typeof(Infinity)都返回number 。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; NaN参与任何数值计算的结构都是NaN，而且 NaN != NaN 。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Infinity / Infinity = NaN 。<br /><br />&nbsp;&nbsp;&nbsp; string:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 面向人类的理性事物，而不是机器信号。人机信息沟通，代码据此理解人的意图等等，都靠它了。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp; 简单类型都不是对象，JavaScript没有将对象化的能力赋予这些简单类型。直接被赋予简单类型常量值的标识符、变量和参数都不是一个对象。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;所谓&ldquo;对象化&rdquo;，就是可以将数据和代码组织成复杂结构的能力。JavaScript中只有object类型和function类型提供了对象化的能力。<br /><br />没有类<br /><br />&nbsp;&nbsp;&nbsp; object就是对象的类型。在JavaScript中不管多么复杂的数据和代码，都可以组织成object形式的对象。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;但JavaScript却没有 &ldquo;类&rdquo;的概念！<br /><br />&nbsp;&nbsp;&nbsp;&nbsp; 对于许多面向对象的程序员来说，这恐怕是JavaScript中最难以理解的地方。是啊，几乎任何讲面向对象的书中，第一个要讲的就是&ldquo;类&rdquo;的概念，这可是面向对象的支柱。这突然没有了&ldquo;类&rdquo;，我们就象一下子没了精神支柱，感到六神无主。看来，要放下对象和类，达到&ldquo;对象本无根，类型亦无形&rdquo;的境界确实是件不容易的事情啊。<br /><br />&nbsp;&nbsp;&nbsp; 这样，我们先来看一段JavaScript程序：</p><div>&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;life&nbsp;=&nbsp;{};<br />&nbsp;&nbsp;&nbsp;&nbsp;for(life.age&nbsp;=&nbsp;1;&nbsp;life.age&nbsp;&lt;=&nbsp;3;&nbsp;life.age++)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;switch(life.age)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;1:&nbsp;life.body&nbsp;=&nbsp;&quot;卵细胞&quot;;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;life.say&nbsp;=&nbsp;function(){alert(this.age+this.body)};<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;2:&nbsp;life.tail&nbsp;=&nbsp;&quot;尾巴&quot;;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;life.gill&nbsp;=&nbsp;&quot;腮&quot;;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;life.body&nbsp;=&nbsp;&quot;蝌蚪&quot;;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;life.say&nbsp;=&nbsp;function(){alert(this.age+this.body+&quot;-&quot;+this.tail+&quot;,&quot;+this.gill)};<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;case&nbsp;3:&nbsp;delete&nbsp;life.tail;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;life.gill;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;life.legs&nbsp;=&nbsp;&quot;四条腿&quot;;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;life.lung&nbsp;=&nbsp;&quot;肺&quot;;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;life.body&nbsp;=&nbsp;&quot;青蛙&quot;;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;life.say&nbsp;=&nbsp;function(){alert(this.age+this.body+&quot;-&quot;+this.legs+&quot;,&quot;+this.lung)};<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;life.say();<br />&nbsp;&nbsp;&nbsp;&nbsp;};</div><p>&nbsp;</p><p><br />&nbsp;&nbsp;&nbsp; 这段JavaScript程序一开始产生了一个生命对象life，life诞生时只是一个光溜溜的对象，没有任何属性和方法。在第一次生命过程中，它有了一个身体属性body，并有了一个say方法，看起来是一个&ldquo;卵细胞&rdquo;。在第二次生命过程中，它又长出了&ldquo;尾巴&rdquo;和&ldquo;腮&rdquo;，有了tail和gill属性，显然它是一个&ldquo;蝌蚪&rdquo;。在第三次生命过程中，它的tail和gill属性消失了，但又长出了&ldquo;四条腿&rdquo;和&ldquo;肺&rdquo;，有了legs和lung属性，从而最终变成了&ldquo;青蛙&rdquo;。如果，你的想像力丰富的话，或许还能让它变成英俊的&ldquo;王子&rdquo;，娶个美丽的&ldquo;公主&rdquo;什么的。不过，在看完这段程序之后，请你思考一个问题：<br /><br />&nbsp;&nbsp;&nbsp; 我们一定需要类吗？<br /><br />&nbsp;&nbsp;&nbsp; 还记得儿时那个&ldquo;小蝌蚪找妈妈&rdquo;的童话吗？也许就在昨天晚，你的孩子刚好是在这个美丽的童话中进入梦乡的吧。可爱的小蝌蚪也就是在其自身类型不断演化过程中，逐渐变成了和妈妈一样的&ldquo;类&rdquo;，从而找到了自己的妈妈。这个童话故事中蕴含的编程哲理就是：对象的&ldquo;类&rdquo;是从无到有，又不断演化，最终又消失于无形之中的...<br /><br />&nbsp;&nbsp;&nbsp; &ldquo;类&rdquo;，的确可以帮助我们理解复杂的现实世界，这纷乱的现实世界也的确需要进行分类。但如果我们的思想被&ldquo;类&rdquo;束缚住了，&ldquo;类&rdquo;也就变成了&ldquo;累&rdquo;。想象一下，如果一个生命对象开始的时就被规定了固定的&ldquo;类&rdquo;，那么它还能演化吗？蝌蚪还能变成青蛙吗？还可以给孩子们讲小蝌蚪找妈妈的故事吗？<br /><br />&nbsp;&nbsp;&nbsp; 所以，JavaScript中没有&ldquo;类&rdquo;，类已化于无形，与对象融为一体。正是由于放下了&ldquo;类&rdquo;这个概念，JavaScript的对象才有了其他编程语言所没有的活力。<br /><br />&nbsp;&nbsp;&nbsp; 如果，此时你的内心深处开始有所感悟，那么你已经逐渐开始理解JavaScript的禅机了。<br /><br />函数的魔力<br /><br />&nbsp;&nbsp;&nbsp; 接下来，我们再讨论一下JavaScript函数的魔力吧。<br /><br />&nbsp;&nbsp;&nbsp; JavaScript的代码就只有function一种形式，function就是函数的类型。也许其他编程语言还有procedure或 method等代码概念，但在JavaScript里只有function一种形式。当我们写下一个函数的时候，只不过是建立了一个function类型的实体而已。请看下面的程序：</p><p>&nbsp;</p><div>&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;myfunc()<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(&quot;hello&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;alert(typeof(myfunc));</div><p>&nbsp;</p><p><br />&nbsp;&nbsp;&nbsp; 这个代码运行之后可以看到typeof(myfunc)返回的是function。以上的函数写法我们称之为&ldquo;定义式&rdquo;的，如果我们将其改写成下面的&ldquo;变量式&rdquo;的，就更容易理解了：</p><p>&nbsp;</p><div>&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;myfunc&nbsp;=&nbsp;function&nbsp;()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(&quot;hello&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;alert(typeof(myfunc));</div><p>&nbsp;</p><p><br />&nbsp;&nbsp;&nbsp; 这里明确定义了一个变量myfunc，它的初始值被赋予了一个function的实体。因此，typeof(myfunc)返回的也是function。其实，这两种函数的写法是等价的，除了一点细微差别，其内部实现完全相同。也就是说，我们写的这些JavaScript函数只是一个命了名的变量而已，其变量类型即为function，变量的值就是我们编写的函数代码体。<br /><br />&nbsp;&nbsp;&nbsp; 聪明的你或许立即会进一步的追问：既然函数只是变量，那么变量就可以被随意赋值并用到任意地方啰？<br /><br />&nbsp;&nbsp;&nbsp; 我们来看看下面的代码：</p><p>&nbsp;</p><div>&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;myfunc&nbsp;=&nbsp;function&nbsp;()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(&quot;hello&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;myfunc();&nbsp;//第一次调用myfunc，输出hello<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;myfunc&nbsp;=&nbsp;function&nbsp;()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(&quot;yeah&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;myfunc();&nbsp;//第二次调用myfunc，将输出yeah</div><p>&nbsp;</p><p><br />&nbsp;&nbsp;&nbsp; 这个程序运行的结果告诉我们：答案是肯定的！在第一次调用函数之后，函数变量又被赋予了新的函数代码体，使得第二次调用该函数时，出现了不同的输出。<br /><br />&nbsp;&nbsp;&nbsp; 好了，我们又来把上面的代码改成第一种定义式的函数形式：</p><p>&nbsp;</p><div>&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;myfunc&nbsp;()<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(&quot;hello&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;myfunc();&nbsp;//这里调用myfunc，输出yeah而不是hello<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;myfunc&nbsp;()<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(&quot;yeah&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;};&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;myfunc();&nbsp;//这里调用myfunc，当然输出yeah</div><p>&nbsp;</p><p><br />&nbsp;&nbsp;&nbsp; 按理说，两个签名完全相同的函数，在其他编程语言中应该是非法的。但在JavaScript中，这没错。不过，程序运行之后却发现一个奇怪的现象：两次调用都只是最后那个函数里输出的值！显然第一个函数没有起到任何作用。这又是为什么呢？<br /><br />&nbsp;&nbsp;&nbsp; 原来，JavaScript执行引擎并非一行一行地分析和执行程序，而是一段一段地分析执行的。而且，在同一段程序的分析执行中，定义式的函数语句会被提取出来优先执行。函数定义执行完之后，才会按顺序执行其他语句代码。也就是说，在第一次调用myfunc之前，第一个函数语句定义的代码逻辑，已被第二个函数定义语句覆盖了。所以，两次都调用都是执行最后一个函数逻辑了。<br /><br />&nbsp;&nbsp;&nbsp; 如果把这个JavaScript代码分成两段，例如将它们写在一个html中，并用&lt;script/&gt;标签将其分成这样的两块：</p><p>&nbsp;</p><div>&lt;script&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;myfunc&nbsp;()<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(&quot;hello&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;myfunc();&nbsp;//这里调用myfunc，输出hello<br />&lt;/script&gt;<br /><br />&lt;script&gt;<br />&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;myfunc&nbsp;()<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(&quot;yeah&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;};&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;myfunc();&nbsp;//这里调用myfunc，输出yeah<br />&lt;/script&gt;</div><p>&nbsp;</p><p><br />&nbsp;&nbsp;&nbsp; 这时，输出才是各自按顺序来的，也证明了JavaScript的确是一段段地执行的。<br /><br />&nbsp;&nbsp;&nbsp; 一段代码中的定义式函数语句会优先执行，这似乎有点象静态语言的编译概念。所以，这一特征也被有些人称为：JavaScript的&ldquo;预编译&rdquo;。<br /><br />&nbsp;&nbsp;&nbsp; 大多数情况下，我们也没有必要去纠缠这些细节问题。只要你记住一点：JavaScript里的代码也是一种数据，同样可以被任意赋值和修改的，而它的值就是代码的逻辑。只是，与一般数据不同的是，函数是可以被调用执行的。<br /><br />&nbsp;&nbsp;&nbsp; 不过，如果JavaScript函数仅仅只有这点道行的话，这与C++的函数指针，DELPHI的方法指针，C#的委托相比，又有啥稀奇嘛！然而， JavaScript函数的神奇之处还体现在另外两个方面：一是函数function类型本身也具有对象化的能力，二是函数function与对象 object超然的结合能力。<br /><br />奇妙的对象<br /><br />&nbsp;&nbsp;&nbsp; 先来说说函数的对象化能力。<br /><br />&nbsp;&nbsp;&nbsp; 任何一个函数都可以为其动态地添加或去除属性，这些属性可以是简单类型，可以是对象，也可以是其他函数。也就是说，函数具有对象的全部特征，你完全可以把函数当对象来用。其实，函数就是对象，只不过比一般的对象多了一个括号&ldquo;()&rdquo;操作符，这个操作符用来执行函数的逻辑。即，函数本身还可以被调用，一般对象却不可以被调用，除此之外完全相同。请看下面的代码：</p><p>&nbsp;</p><div>&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;Sing()<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;with(arguments.callee)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(author&nbsp;+&nbsp;&quot;：&quot;&nbsp;+&nbsp;poem);<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;Sing.author&nbsp;=&nbsp;&quot;李白&quot;;<br />&nbsp;&nbsp;&nbsp;&nbsp;Sing.poem&nbsp;=&nbsp;&quot;汉家秦地月，流影照明妃。一上玉关道，天涯去不归<img alt="" src="http://www.cnblogs.com/Images/dot.gif" />&quot;;<br />&nbsp;&nbsp;&nbsp;&nbsp;Sing();<br />&nbsp;&nbsp;&nbsp;&nbsp;Sing.author&nbsp;=&nbsp;&quot;李战&quot;;<br />&nbsp;&nbsp;&nbsp;&nbsp;Sing.poem&nbsp;=&nbsp;&quot;日出汉家天，月落阴山前。女儿琵琶怨，已唱三千年<img alt="" src="http://www.cnblogs.com/Images/dot.gif" />&quot;;<br />&nbsp;&nbsp;&nbsp;&nbsp;Sing();</div><p>&nbsp;</p><p><br />&nbsp;&nbsp;&nbsp; 在这段代码中，Sing函数被定义后，又给Sing函数动态地增加了author和poem属性。将author和poem属性设为不同的作者和诗句，在调用Sing()时就能显示出不同的结果。这个示例用一种诗情画意的方式，让我们理解了JavaScript函数就是对象的本质，也感受到了 JavaScript语言的优美。<br /><br />&nbsp;&nbsp;&nbsp; 好了，以上的讲述，我们应该算理解了function类型的东西都是和object类型一样的东西，这种东西被我们称为&ldquo;对象&rdquo;。我们的确可以这样去看待这些&ldquo;对象&rdquo;，因为它们既有&ldquo;属性&rdquo;也有&ldquo;方法&rdquo;嘛。但下面的代码又会让我们产生新的疑惑：</p><p>&nbsp;</p><div>&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;anObject&nbsp;=&nbsp;{};&nbsp;&nbsp;//一个对象<br />&nbsp;&nbsp;&nbsp;&nbsp;anObject.aProperty&nbsp;=&nbsp;&quot;Property&nbsp;of&nbsp;object&quot;;&nbsp;&nbsp;//对象的一个属性<br />&nbsp;&nbsp;&nbsp;&nbsp;anObject.aMethod&nbsp;=&nbsp;function(){alert(&quot;Method&nbsp;of&nbsp;object&quot;)};&nbsp;//对象的一个方法<br />&nbsp;&nbsp;&nbsp;&nbsp;//主要看下面：<br />&nbsp;&nbsp;&nbsp;&nbsp;alert(anObject[&quot;aProperty&quot;]);&nbsp;&nbsp;&nbsp;//可以将对象当数组以属性名作为下标来访问属性<br />&nbsp;&nbsp;&nbsp;&nbsp;anObject[&quot;aMethod&quot;]();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//可以将对象当数组以方法名作为下标来调用方法<br />&nbsp;&nbsp;&nbsp;&nbsp;for(&nbsp;var&nbsp;s&nbsp;in&nbsp;anObject)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//遍历对象的所有属性和方法进行迭代化处理<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(s&nbsp;+&nbsp;&quot;&nbsp;is&nbsp;a&nbsp;&quot;&nbsp;+&nbsp;typeof(anObject[s]));</div><p>&nbsp;</p><p><br />&nbsp;&nbsp;&nbsp; 同样对于function类型的对象也是一样：</p><p>&nbsp;</p><div>&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;aFunction&nbsp;= function() {};&nbsp;&nbsp;//一个函数<br />&nbsp;&nbsp;&nbsp;&nbsp;aFunction.aProperty&nbsp;=&nbsp;&quot;Property&nbsp;of&nbsp;function&quot;;&nbsp;&nbsp;//函数的一个属性<br />&nbsp;&nbsp;&nbsp;&nbsp;aFunction.aMethod&nbsp;=&nbsp;function(){alert(&quot;Method&nbsp;of&nbsp;function&quot;)};&nbsp;//函数的一个方法<br />&nbsp;&nbsp;&nbsp;&nbsp;//主要看下面：<br />&nbsp;&nbsp;&nbsp;&nbsp;alert(aFunction[&quot;aProperty&quot;]);&nbsp;&nbsp;&nbsp;//可以将函数当数组以属性名作为下标来访问属性<br />&nbsp;&nbsp;&nbsp;&nbsp;aFunction[&quot;aMethod&quot;]();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//可以将函数当数组以方法名作为下标来调用方法<br />&nbsp;&nbsp;&nbsp;&nbsp;for(&nbsp;var&nbsp;s&nbsp;in&nbsp;aFunction)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//遍历函数的所有属性和方法进行迭代化处理<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(s&nbsp;+&nbsp;&quot;&nbsp;is&nbsp;a&nbsp;&quot;&nbsp;+&nbsp;typeof(aFunction[s]));</div><p>&nbsp;</p><p><br />&nbsp;&nbsp;&nbsp; 是的，对象和函数可以象数组一样，用属性名或方法名作为下标来访问并处理。那么，它到底应该算是数组呢，还是算对象？<br /><br />&nbsp;&nbsp;&nbsp; 我们知道，数组应该算是线性数据结构，线性数据结构一般有一定的规律，适合进行统一的批量迭代操作等，有点像波。而对象是离散数据结构，适合描述分散的和个性化的东西，有点像粒子。因此，我们也可以这样问：JavaScript里的对象到底是波还是粒子？<br /><br />&nbsp;&nbsp;&nbsp; 如果存在对象量子论，那么答案一定是：波粒二象性！<br /><br />&nbsp;&nbsp;&nbsp; 因此，JavaScript里的函数和对象既有对象的特征也有数组的特征。这里的数组被称为&ldquo;字典&rdquo;，一种可以任意伸缩的名称值对儿的集合。其实， object和function的内部实现就是一个字典结构，但这种字典结构却通过严谨而精巧的语法表现出了丰富的外观。正如量子力学在一些地方用粒子来解释和处理问题，而在另一些地方却用波来解释和处理问题。你也可以在需要的时候，自由选择用对象还是数组来解释和处理问题。只要善于把握 JavaScript的这些奇妙特性，就可以编写出很多简洁而强大的代码来。<br /><br />放下对象<br /><br />&nbsp;&nbsp;&nbsp; 我们再来看看function与object的超然结合吧。<br /><br />&nbsp;&nbsp;&nbsp; 在面向对象的编程世界里，数据与代码的有机结合就构成了对象的概念。自从有了对象，编程世界就被划分成两部分，一个是对象内的世界，一个是对象外的世界。对象天生具有自私的一面，外面的世界未经允许是不可访问对象内部的。对象也有大方的一面，它对外提供属性和方法，也为他人服务。不过，在这里我们要谈到一个有趣的问题，就是&ldquo;对象的自我意识&rdquo;。<br /><br />&nbsp;&nbsp;&nbsp; 什么？没听错吧？对象有自我意识？<br /><br />&nbsp;&nbsp;&nbsp; 可能对许多程序员来说，这的确是第一次听说。不过，请君看看C++、C#和Java的this，DELPHI的self，还有VB的me，或许你会恍然大悟！当然，也可能只是说句&ldquo;不过如此&rdquo;而已。<br /><br />&nbsp;&nbsp;&nbsp; 然而，就在对象将世界划分为内外两部分的同时，对象的&ldquo;自我&rdquo;也就随之产生。&ldquo;自我意识&rdquo;是生命的最基本特征！正是由于对象这种强大的生命力，才使得编程世界充满无限的生机和活力。<br /><br />&nbsp;&nbsp;&nbsp; 但对象的&ldquo;自我意识&rdquo;在带给我们快乐的同时也带来了痛苦和烦恼。我们给对象赋予了太多欲望，总希望它们能做更多的事情。然而，对象的自私使得它们互相争抢系统资源，对象的自负让对象变得复杂和臃肿，对象的自欺也往往带来挥之不去的错误和异常。我们为什么会有这么多的痛苦和烦恼呢？<br />&nbsp;<br />&nbsp;&nbsp;&nbsp; 为此，有一个人，在对象树下，整整想了九九八十一天，终于悟出了生命的痛苦来自于欲望，但究其欲望的根源是来自于自我意识。于是他放下了&ldquo;自我&rdquo;，在对象树下成了佛，从此他开始普度众生，传播真经。他的名字就叫释迦摩尼，而《JavaScript真经》正是他所传经书中的一本。<br /><br />&nbsp;&nbsp;&nbsp; JavaScript中也有this，但这个this却与C++、C#或Java等语言的this不同。一般编程语言的this就是对象自己，而 JavaScript的this却并不一定！this可能是我，也可能是你，可能是他，反正是我中有你，你中有我，这就不能用原来的那个&ldquo;自我&rdquo;来理解 JavaScript这个this的含义了。为此，我们必须首先放下原来对象的那个&ldquo;自我&rdquo;。<br /><br />&nbsp;&nbsp;&nbsp; 我们来看下面的代码：</p><p>&nbsp;</p><div>&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;WhoAmI()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//定义一个函数WhoAmI<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(&quot;I'm&nbsp;&quot;&nbsp;+&nbsp;this.name&nbsp;+&nbsp;&quot;&nbsp;of&nbsp;&quot;&nbsp;+&nbsp;typeof(this));<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;WhoAmI();&nbsp;&nbsp;&nbsp;//此时是this当前这段代码的全局对象，在浏览器中就是window对象，其name属性为空字符串。输出：I'm&nbsp;of&nbsp;object<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;BillGates&nbsp;=&nbsp;{name:&nbsp;&quot;Bill&nbsp;Gates&quot;};<br />&nbsp;&nbsp;&nbsp;&nbsp;BillGates.WhoAmI&nbsp;=&nbsp;WhoAmI;&nbsp;&nbsp;//将函数WhoAmI作为BillGates的方法。<br />&nbsp;&nbsp;&nbsp;&nbsp;BillGates.WhoAmI();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//此时的this是BillGates。输出：I'm&nbsp;Bill&nbsp;Gates&nbsp;of&nbsp;object<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;SteveJobs&nbsp;=&nbsp;{name:&nbsp;&quot;Steve&nbsp;Jobs&quot;};<br />&nbsp;&nbsp;&nbsp;&nbsp;SteveJobs.WhoAmI&nbsp;=&nbsp;WhoAmI;&nbsp;&nbsp;//将函数WhoAmI作为SteveJobs的方法。<br />&nbsp;&nbsp;&nbsp;&nbsp;SteveJobs.WhoAmI();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//此时的this是SteveJobs。输出：I'm&nbsp;Steve&nbsp;Jobs&nbsp;of&nbsp;object<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;WhoAmI.call(BillGates);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//直接将BillGates作为this，调用WhoAmI。输出：I'm&nbsp;Bill&nbsp;Gates&nbsp;of&nbsp;object<br />&nbsp;&nbsp;&nbsp;&nbsp;WhoAmI.call(SteveJobs);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//直接将SteveJobs作为this，调用WhoAmI。输出：I'm&nbsp;Steve&nbsp;Jobs&nbsp;of&nbsp;object<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;BillGates.WhoAmI.call(SteveJobs);&nbsp;&nbsp;&nbsp;//将SteveJobs作为this，却调用BillGates的WhoAmI方法。输出：I'm&nbsp;Steve&nbsp;Jobs&nbsp;of&nbsp;object<br />&nbsp;&nbsp;&nbsp;&nbsp;SteveJobs.WhoAmI.call(BillGates);&nbsp;&nbsp;&nbsp;//将BillGates作为this，却调用SteveJobs的WhoAmI方法。输出：I'm&nbsp;Bill&nbsp;Gates&nbsp;of&nbsp;object<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;WhoAmI.WhoAmI&nbsp;=&nbsp;WhoAmI;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//将WhoAmI函数设置为自身的方法。<br />&nbsp;&nbsp;&nbsp;&nbsp;WhoAmI.name&nbsp;=&nbsp;&quot;WhoAmI&quot;;<br />&nbsp;&nbsp;&nbsp;&nbsp;WhoAmI.WhoAmI();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//此时的this是WhoAmI函数自己。输出：I'm&nbsp;WhoAmI&nbsp;of&nbsp;function<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;({name:&nbsp;&quot;nobody&quot;,&nbsp;WhoAmI:&nbsp;WhoAmI}).WhoAmI();&nbsp;&nbsp;&nbsp;&nbsp;//临时创建一个匿名对象并设置属性后调用WhoAmI方法。输出：I'm&nbsp;nobody&nbsp;of&nbsp;object</div><p>&nbsp;</p><p><br />&nbsp;&nbsp;&nbsp; 从上面的代码可以看出，同一个函数可以从不同的角度来调用，this并不一定是函数本身所属的对象。this只是在任意对象和function元素结合时的一个概念，是种结合比起一般对象语言的默认结合更加灵活，显得更加超然和洒脱。<br /><br />&nbsp;&nbsp;&nbsp; 在JavaScript函数中，你只能把this看成当前要服务的&ldquo;这个&rdquo;对象。this是一个特殊的内置参数，根据this参数，您可以访问到&ldquo;这个&rdquo; 对象的属性和方法，但却不能给this参数赋值。在一般对象语言中，方法体代码中的this可以省略的，成员默认都首先是&ldquo;自己&rdquo;的。但 JavaScript却不同，由于不存在&ldquo;自我&rdquo;，当访问&ldquo;这个&rdquo;对象时，this不可省略！<br /><br />&nbsp;&nbsp;&nbsp; JavaScript提供了传递this参数的多种形式和手段，其中，象BillGates.WhoAmI()和SteveJobs.WhoAmI()这种形式，是传递this参数最正规的形式，此时的this就是函数所属的对象本身。而大多数情况下，我们也几乎很少去采用那些借花仙佛的调用形式。但只我们要明白JavaScript的这个&ldquo;自我&rdquo;与其他编程语言的&ldquo;自我&rdquo;是不同的，这是一个放下了的&ldquo;自我&rdquo;，这就是JavaScript特有的世界观。<br /><br />对象素描<br /><br />&nbsp;&nbsp;&nbsp; 已经说了许多了许多话题了，但有一个很基本的问题我们忘了讨论，那就是：怎样建立对象？<br /><br />&nbsp;&nbsp;&nbsp; 在前面的示例中，我们已经涉及到了对象的建立了。我们使用了一种被称为JavaScript Object Notation(缩写JSON)的形式，翻译为中文就是&ldquo;JavaScript对象表示法&rdquo;。<br /><br />&nbsp;&nbsp;&nbsp; JSON为创建对象提供了非常简单的方法。例如，<br />&nbsp;&nbsp;&nbsp; 创建一个没有任何属性的对象：</p><p>&nbsp;</p><div>var&nbsp;o&nbsp;=&nbsp;{};</div><p>&nbsp;</p><p><br />&nbsp;&nbsp;&nbsp; 创建一个对象并设置属性及初始值：</p><p>&nbsp;</p><div>var&nbsp;person&nbsp;=&nbsp;{name:&nbsp;&quot;Angel&quot;,&nbsp;age:&nbsp;18,&nbsp;married:&nbsp;false};</div><p>&nbsp;</p><p><br />&nbsp;&nbsp;&nbsp; 创建一个对象并设置属性和方法：</p><p>&nbsp;</p><div>var&nbsp;speaker&nbsp;=&nbsp;{text:&nbsp;&quot;Hello&nbsp;World&quot;,&nbsp;say:&nbsp;function(){alert(this.text)}};</div><p>&nbsp;</p><p><br />&nbsp;&nbsp;&nbsp;&nbsp; 创建一个更复杂的对象，嵌套其他对象和对象数组等：</p><p>&nbsp;</p><div>&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;company&nbsp;=<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;name:&nbsp;&quot;Microsoft&quot;,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;product:&nbsp;&quot;softwares&quot;,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chairman:&nbsp;{name:&nbsp;&quot;Bill&nbsp;Gates&quot;,&nbsp;age:&nbsp;53,&nbsp;Married:&nbsp;true},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;employees:&nbsp;[{name:&nbsp;&quot;Angel&quot;,&nbsp;age:&nbsp;26,&nbsp;Married:&nbsp;false},&nbsp;{name:&nbsp;&quot;Hanson&quot;,&nbsp;age:&nbsp;32,&nbsp;Marred:&nbsp;true}],<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;readme:&nbsp;function()&nbsp;{document.write(this.name&nbsp;+&nbsp;&quot;&nbsp;product&nbsp;&quot;&nbsp;+&nbsp;this.product);}<br />&nbsp;&nbsp;&nbsp;&nbsp;};</div><p>&nbsp;</p><p><br />&nbsp;&nbsp;&nbsp; JSON的形式就是用大括&ldquo;{}&rdquo;号包括起来的项目列表，每一个项目间并用逗号&ldquo;,&rdquo;分隔，而项目就是用冒号&ldquo;:&rdquo;分隔的属性名和属性值。这是典型的字典表示形式，也再次表明了 JavaScript里的对象就是字典结构。不管多么复杂的对象，都可以被一句JSON代码来创建并赋值。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp; 其实，JSON就是JavaScript对象最好的序列化形式，它比XML更简洁也更省空间。对象可以作为一个JSON形式的字符串，在网络间自由传递和交换信息。而当需要将这个JSON字符串变成一个JavaScript对象时，只需要使用eval函数这个强大的数码转换引擎，就立即能得到一个 JavaScript内存对象。正是由于JSON的这种简单朴素的天生丽质，才使得她在AJAX舞台上成为璀璨夺目的明星。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;JavaScript就是这样，把面向对象那些看似复杂的东西，用及其简洁的形式表达出来。卸下对象浮华的浓妆，还对象一个眉目清晰！<br /><br />构造对象<br />&nbsp;<br />&nbsp;&nbsp;&nbsp; 好了，接下我们来讨论一下对象的另一种创建方法。<br /><br />&nbsp;&nbsp;&nbsp; 除JSON外，在JavaScript中我们可以使用new操作符结合一个函数的形式来创建对象。例如：</p><p>&nbsp;</p><div>&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;MyFunc()&nbsp;{};&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//定义一个空函数<br />&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;anObj&nbsp;=&nbsp;new&nbsp;MyFunc();&nbsp;&nbsp;//使用new操作符，借助MyFun函数，就创建了一个对象</div><p>&nbsp;</p><p><br />&nbsp;&nbsp;&nbsp; JavaScript的这种创建对象的方式可真有意思，如何去理解这种写法呢？<br />&nbsp;<br />&nbsp;&nbsp; 其实，可以把上面的代码改写成这种等价形式：</p><p>&nbsp;</p><div>&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;MyFunc(){};<br />&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;anObj&nbsp;=&nbsp;{};&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//创建一个对象<br />&nbsp;&nbsp;&nbsp;&nbsp;MyFunc.call(anObj);&nbsp;//将anObj对象作为this指针调用MyFunc函数</div><p>&nbsp;</p><p><br />&nbsp;&nbsp;&nbsp; 我们就可以这样理解，JavaScript先用new操作符创建了一个对象，紧接着就将这个对象作为this参数调用了后面的函数。其实， JavaScript内部就是这么做的，而且任何函数都可以被这样调用！但从 &ldquo;anObj = new MyFunc()&rdquo; 这种形式，我们又看到一个熟悉的身影，C++和C#不就是这样创建对象的吗？原来，条条大路通灵山，殊途同归啊！<br /><br />&nbsp;&nbsp;&nbsp; 君看到此处也许会想，我们为什么不可以把这个MyFunc当作构造函数呢？恭喜你，答对了！JavaScript也是这么想的！请看下面的代码：&nbsp;</p><p>&nbsp;</p><div>&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;Person(name)&nbsp;&nbsp;&nbsp;//带参数的构造函数<br />&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.name&nbsp;=&nbsp;name;&nbsp;&nbsp;&nbsp;//将参数值赋给给this对象的属性<br />&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.SayHello&nbsp;=&nbsp;function()&nbsp;{alert(&quot;Hello,&nbsp;I'm&nbsp;&quot;&nbsp;+&nbsp;this.name);};&nbsp;&nbsp;&nbsp;//给this对象定义一个SayHello方法。<br />&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;6&nbsp;<br />&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;Employee(name,&nbsp;salary)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//子构造函数<br />&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Person.call(this,&nbsp;name);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//将this传给父构造函数<br />10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.salary&nbsp;=&nbsp;salary;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//设置一个this的salary属性<br />11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.ShowMeTheMoney&nbsp;=&nbsp;function()&nbsp;{alert(this.name&nbsp;+&nbsp;&quot;&nbsp;$&quot;&nbsp;+&nbsp;this.salary);};&nbsp;&nbsp;//添加ShowMeTheMoney方法。<br />12&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br />13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />14&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;BillGates&nbsp;=&nbsp;new&nbsp;Person(&quot;Bill&nbsp;Gates&quot;);&nbsp;&nbsp;&nbsp;//用Person构造函数创建BillGates对象<br />15&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;SteveJobs&nbsp;=&nbsp;new&nbsp;Employee(&quot;Steve&nbsp;Jobs&quot;,&nbsp;1234);&nbsp;&nbsp;&nbsp;//用Empolyee构造函数创建SteveJobs对象<br />16&nbsp;<br />17&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BillGates.SayHello();&nbsp;&nbsp;&nbsp;//显示：I'm&nbsp;Bill&nbsp;Gates<br />18&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SteveJobs.SayHello();&nbsp;&nbsp;&nbsp;//显示：I'm&nbsp;Steve&nbsp;Jobs<br />19&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SteveJobs.ShowMeTheMoney();&nbsp;&nbsp;&nbsp;//显示：Steve&nbsp;Jobs&nbsp;$1234<br />20&nbsp;<br />21&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(BillGates.constructor&nbsp;==&nbsp;Person);&nbsp;&nbsp;//显示：true<br />22&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(SteveJobs.constructor&nbsp;==&nbsp;Employee);&nbsp;&nbsp;//显示：true<br />23&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />24&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(BillGates.SayHello&nbsp;==&nbsp;SteveJobs.SayHello);&nbsp;//显示：false</div><p>&nbsp;</p><p><br />&nbsp;&nbsp;&nbsp; 这段代码表明，函数不但可以当作构造函数，而且还可以带参数，还可以为对象添加成员和方法。其中的第9行，Employee构造函数又将自己接收的 this作为参数调用Person构造函数，这就是相当于调用基类的构造函数。第21、22行还表明这样一个意思：BillGates是由Person构造的，而SteveJobs是由Employee构造的。对象内置的constructor属性还指明了构造对象所用的具体函数！<br /><br />&nbsp;&nbsp;&nbsp; 其实，如果你愿意把函数当作&ldquo;类&rdquo;的话，她就是&ldquo;类&rdquo;，因为她本来就有&ldquo;类&rdquo;的那些特征。难道不是吗？她生出的儿子各个都有相同的特征，而且构造函数也与类同名嘛！<br /><br />&nbsp;&nbsp;&nbsp; 但要注意的是，用构造函数操作this对象创建出来的每一个对象，不但具有各自的成员数据，而且还具有各自的方法数据。换句话说，方法的代码体(体现函数逻辑的数据)在每一个对象中都存在一个副本。尽管每一个代码副本的逻辑是相同的，但对象们确实是各自保存了一份代码体。上例中的最后一句说明了这一实事，这也解释了JavaScript中的函数就是对象的概念。<br /><br />&nbsp;&nbsp;&nbsp; 同一类的对象各自有一份方法代码显然是一种浪费。在传统的对象语言中，方法函数并不象JavaScript那样是个对象概念。即使也有象函数指针、方法指针或委托那样的变化形式，但其实质也是对同一份代码的引用。一般的对象语言很难遇到这种情况。<br /><br />&nbsp;&nbsp;&nbsp; 不过，JavaScript语言有大的灵活性。我们可以先定义一份唯一的方法函数体，并在构造this对象时使用这唯一的函数对象作为其方法，就能共享方法逻辑。例如：</p><p>&nbsp;</p><div>&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;SayHello()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//先定义一份SayHello函数代码<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(&quot;Hello,&nbsp;I'm&nbsp;&quot;&nbsp;+&nbsp;this.name);<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;Person(name)&nbsp;&nbsp;&nbsp;//带参数的构造函数<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.name&nbsp;=&nbsp;name;&nbsp;&nbsp;&nbsp;//将参数值赋给给this对象的属性<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.SayHello&nbsp;=&nbsp;SayHello;&nbsp;&nbsp;&nbsp;//给this对象SayHello方法赋值为前面那份SayHello代码。<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;BillGates&nbsp;=&nbsp;new&nbsp;Person(&quot;Bill&nbsp;Gates&quot;);&nbsp;&nbsp;&nbsp;//创建BillGates对象<br />&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;SteveJobs&nbsp;=&nbsp;new&nbsp;Person(&quot;Steve&nbsp;Jobs&quot;);&nbsp;&nbsp;&nbsp;//创建SteveJobs对象<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;alert(BillGates.SayHello&nbsp;==&nbsp;SteveJobs.SayHello);&nbsp;//显示：true</div><p>&nbsp;</p><p><br />&nbsp;&nbsp;&nbsp;&nbsp; 其中，最后一行的输出结果表明两个对象确实共享了一个函数对象。虽然，这段程序达到了共享了一份方法代码的目的，但却不怎么优雅。因为，定义 SayHello方法时反映不出其与Person类的关系。&ldquo;优雅&rdquo;这个词用来形容代码，也不知道是谁先提出来的。不过，这个词反映了程序员已经从追求代码的正确、高效、可靠和易读等基础上，向着追求代码的美观感觉和艺术境界的层次发展，程序人生又多了些浪漫色彩。<br /><br />&nbsp;&nbsp; 显然，JavaScript早想到了这一问题，她的设计者们为此提供了一个有趣的prototype概念。<br /><br />初看原型<br /><br />&nbsp;&nbsp;&nbsp; prototype源自法语，软件界的标准翻译为&ldquo;原型&rdquo;，代表事物的初始形态，也含有模型和样板的意义。JavaScript中的prototype概念恰如其分地反映了这个词的内含，我们不能将其理解为C++的prototype那种预先声明的概念。<br /><br />&nbsp;&nbsp;&nbsp; JavaScript的所有function类型的对象都有一个prototype属性。这个prototype属性本身又是一个object类型的对象，因此我们也可以给这个prototype对象添加任意的属性和方法。既然prototype是对象的&ldquo;原型&rdquo;，那么由该函数构造出来的对象应该都会具有这个&ldquo;原型&rdquo;的特性。事实上，在构造函数的prototype上定义的所有属性和方法，都是可以通过其构造的对象直接访问和调用的。也可以这么说， prototype提供了一群同类对象共享属性和方法的机制。<br /><br />&nbsp;&nbsp;&nbsp; 我们先来看看下面的代码：</p><p>&nbsp;</p><div>&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;Person(name)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.name&nbsp;=&nbsp;name;&nbsp;&nbsp;&nbsp;//设置对象属性，每个对象各自一份属性数据<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;Person.prototype.SayHello&nbsp;=&nbsp;function()&nbsp;&nbsp;//给Person函数的prototype添加SayHello方法。<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(&quot;Hello,&nbsp;I'm&nbsp;&quot;&nbsp;+&nbsp;this.name);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;BillGates&nbsp;=&nbsp;new&nbsp;Person(&quot;Bill&nbsp;Gates&quot;);&nbsp;&nbsp;&nbsp;//创建BillGates对象<br />&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;SteveJobs&nbsp;=&nbsp;new&nbsp;Person(&quot;Steve&nbsp;Jobs&quot;);&nbsp;&nbsp;&nbsp;//创建SteveJobs对象<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;BillGates.SayHello();&nbsp;&nbsp;&nbsp;//通过BillGates对象直接调用到SayHello方法<br />&nbsp;&nbsp;&nbsp;&nbsp;SteveJobs.SayHello();&nbsp;&nbsp;&nbsp;//通过SteveJobs对象直接调用到SayHello方法<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;alert(BillGates.SayHello&nbsp;==&nbsp;SteveJobs.SayHello);&nbsp;//因为两个对象是共享prototype的SayHello，所以显示：true</div><p>&nbsp;</p><p><br />&nbsp;&nbsp;&nbsp; 程序运行的结果表明，构造函数的prototype上定义的方法确实可以通过对象直接调用到，而且代码是共享的。显然，把方法设置到prototype的写法显得优雅多了，尽管调用形式没有变，但逻辑上却体现了方法与类的关系，相对前面的写法，更容易理解和组织代码。<br /><br />&nbsp;&nbsp;&nbsp; 那么，对于多层次类型的构造函数情况又如何呢？<br /><br />&nbsp;&nbsp;&nbsp; 我们再来看下面的代码：</p><p>&nbsp;</p><div>&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;Person(name)&nbsp;&nbsp;&nbsp;//基类构造函数<br />&nbsp;2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.name&nbsp;=&nbsp;name;<br />&nbsp;4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;6&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Person.prototype.SayHello&nbsp;=&nbsp;function()&nbsp;&nbsp;//给基类构造函数的prototype添加方法<br />&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(&quot;Hello,&nbsp;I'm&nbsp;&quot;&nbsp;+&nbsp;this.name);<br />&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br />10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />11&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;Employee(name,&nbsp;salary)&nbsp;//子类构造函数<br />12&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />13&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Person.call(this,&nbsp;name);&nbsp;&nbsp;&nbsp;&nbsp;//调用基类构造函数<br />14&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.salary&nbsp;=&nbsp;salary;<br />15&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br />16&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />17&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Employee.prototype&nbsp;=&nbsp;new&nbsp;Person();&nbsp;&nbsp;//建一个基类的对象作为子类原型的原型，这里很有意思<br />18&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />19&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Employee.prototype.ShowMeTheMoney&nbsp;=&nbsp;function()&nbsp;&nbsp;//给子类添构造函数的prototype添加方法<br />20&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />21&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(this.name&nbsp;+&nbsp;&quot;&nbsp;$&quot;&nbsp;+&nbsp;this.salary);<br />22&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br />23&nbsp;<br />24&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;BillGates&nbsp;=&nbsp;new&nbsp;Person(&quot;Bill&nbsp;Gates&quot;);&nbsp;&nbsp;&nbsp;//创建基类Person的BillGates对象<br />25&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;SteveJobs&nbsp;=&nbsp;new&nbsp;Employee(&quot;Steve&nbsp;Jobs&quot;,&nbsp;1234);&nbsp;&nbsp;&nbsp;//创建子类Employee的SteveJobs对象<br />26&nbsp;<br />27&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BillGates.SayHello();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//通过对象直接调用到prototype的方法<br />28&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SteveJobs.SayHello();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//通过子类对象直接调用基类prototype的方法，关注！<br />29&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SteveJobs.ShowMeTheMoney();&nbsp;//通过子类对象直接调用子类prototype的方法<br />30&nbsp;<br />31&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(BillGates.SayHello&nbsp;==&nbsp;SteveJobs.SayHello);&nbsp;//显示：true，表明prototype的方法是共享的</div><p>&nbsp;</p><p><br />&nbsp;&nbsp;&nbsp; 这段代码的第17行，构造了一个基类的对象，并将其设为子类构造函数的prototype，这是很有意思的。这样做的目的就是为了第28行，通过子类对象也可以直接调用基类prototype的方法。为什么可以这样呢？<br /><br />&nbsp;&nbsp;&nbsp; 原来，在JavaScript中，prototype不但能让对象共享自己财富，而且prototype还有寻根问祖的天性，从而使得先辈们的遗产可以代代相传。当从一个对象那里读取属性或调用方法时，如果该对象自身不存在这样的属性或方法，就会去自己关联的prototype对象那里寻找；如果 prototype没有，又会去prototype自己关联的前辈prototype那里寻找，直到找到或追溯过程结束为止。<br /><br />&nbsp;&nbsp;&nbsp; 在JavaScript内部，对象的属性和方法追溯机制是通过所谓的prototype链来实现的。当用new操作符构造对象时，也会同时将构造函数的 prototype对象指派给新创建的对象，成为该对象内置的原型对象。对象内置的原型对象应该是对外不可见的，尽管有些浏览器(如Firefox)可以让我们访问这个内置原型对象，但并不建议这样做。内置的原型对象本身也是对象，也有自己关联的原型对象，这样就形成了所谓的原型链。<br /><br />&nbsp;&nbsp;&nbsp; 在原型链的最末端，就是Object构造函数prototype属性指向的那一个原型对象。这个原型对象是所有对象的最老祖先，这个老祖宗实现了诸如 toString等所有对象天生就该具有的方法。其他内置构造函数，如Function, Boolean, String, Date和RegExp等的prototype都是从这个老祖宗传承下来的，但他们各自又定义了自身的属性和方法，从而他们的子孙就表现出各自宗族的那些特征。<br /><br />&nbsp;&nbsp;&nbsp; 这不就是&ldquo;继承&rdquo;吗？是的，这就是&ldquo;继承&rdquo;，是JavaScript特有的&ldquo;原型继承&rdquo;。<br /><br />&nbsp;&nbsp;&nbsp; &ldquo;原型继承&rdquo;是慈祥而又严厉的。原形对象将自己的属性和方法无私地贡献给孩子们使用，也并不强迫孩子们必须遵从，允许一些顽皮孩子按自己的兴趣和爱好独立行事。从这点上看，原型对象是一位慈祥的母亲。然而，任何一个孩子虽然可以我行我素，但却不能动原型对象既有的财产，因为那可能会影响到其他孩子的利益。从这一点上看，原型对象又象一位严厉的父亲。我们来看看下面的代码就可以理解这个意思了：</p><p>&nbsp;</p><div>&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;Person(name)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.name&nbsp;=&nbsp;name;<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;Person.prototype.company&nbsp;=&nbsp;&quot;Microsoft&quot;;&nbsp;//原型的属性<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;Person.prototype.SayHello&nbsp;=&nbsp;function()&nbsp;&nbsp;//原型的方法<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(&quot;Hello,&nbsp;I'm&nbsp;&quot;&nbsp;+&nbsp;this.name&nbsp;+&nbsp;&quot;&nbsp;of&nbsp;&quot;&nbsp;+&nbsp;this.company);<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;BillGates&nbsp;=&nbsp;new&nbsp;Person(&quot;Bill&nbsp;Gates&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;BillGates.SayHello();&nbsp;&nbsp;&nbsp;//由于继承了原型的东西，规规矩矩输出：Hello,&nbsp;I'm&nbsp;Bill&nbsp;Gates<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;SteveJobs&nbsp;=&nbsp;new&nbsp;Person(&quot;Steve&nbsp;Jobs&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;SteveJobs.company&nbsp;=&nbsp;&quot;Apple&quot;;&nbsp;&nbsp;&nbsp;&nbsp;//设置自己的company属性，掩盖了原型的company属性<br />&nbsp;&nbsp;&nbsp;&nbsp;SteveJobs.SayHello&nbsp;=&nbsp;function()&nbsp;//实现了自己的SayHello方法，掩盖了原型的SayHello方法<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(&quot;Hi,&nbsp;&quot;&nbsp;+&nbsp;this.name&nbsp;+&nbsp;&quot;&nbsp;like&nbsp;&quot;&nbsp;+&nbsp;this.company&nbsp;+&nbsp;&quot;,&nbsp;ha&nbsp;ha&nbsp;ha&nbsp;&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;SteveJobs.SayHello();&nbsp;&nbsp;&nbsp;//都是自己覆盖的属性和方法，输出：Hi,&nbsp;Steve&nbsp;Jobs&nbsp;like&nbsp;Apple,&nbsp;ha&nbsp;ha&nbsp;ha&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;BillGates.SayHello();&nbsp;&nbsp;&nbsp;//SteveJobs的覆盖没有影响原型对象，BillGates还是按老样子输出</div><p>&nbsp;</p><p><br />&nbsp;&nbsp;&nbsp; 对象可以掩盖原型对象的那些属性和方法，一个构造函数原型对象也可以掩盖上层构造函数原型对象既有的属性和方法。这种掩盖其实只是在对象自己身上创建了新的属性和方法，只不过这些属性和方法与原型对象的那些同名而已。JavaScript就是用这简单的掩盖机制实现了对象的&ldquo;多态&rdquo;性，与静态对象语言的虚函数和重载(override)概念不谋而合。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;然而，比静态对象语言更神奇的是，我们可以随时给原型对象动态添加新的属性和方法，从而动态地扩展基类的功能特性。这在静态对象语言中是很难想象的。我们来看下面的代码：</p><p>&nbsp;</p><div>&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;Person(name)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.name&nbsp;=&nbsp;name;<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;Person.prototype.SayHello&nbsp;=&nbsp;function()&nbsp;&nbsp;//建立对象前定义的方法<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(&quot;Hello,&nbsp;I'm&nbsp;&quot;&nbsp;+&nbsp;this.name);<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;BillGates&nbsp;=&nbsp;new&nbsp;Person(&quot;Bill&nbsp;Gates&quot;);&nbsp;&nbsp;&nbsp;//建立对象<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;BillGates.SayHello();<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;Person.prototype.Retire&nbsp;=&nbsp;function()&nbsp;&nbsp;&nbsp;&nbsp;//建立对象后再动态扩展原型的方法<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(&quot;Poor&nbsp;&quot;&nbsp;+&nbsp;this.name&nbsp;+&nbsp;&quot;,&nbsp;bye&nbsp;bye!&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;BillGates.Retire();&nbsp;//动态扩展的方法即可被先前建立的对象立即调用</div><p>&nbsp;</p><p><br />&nbsp;&nbsp;&nbsp;&nbsp;阿弥佗佛，原型继承竟然可以玩出有这样的法术！<br /><br />原型扩展<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;想必君的悟性极高，可能你会这样想：如果在JavaScript内置的那些如Object和Function等函数的prototype上添加些新的方法和属性，是不是就能扩展JavaScript的功能呢？<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;那么，恭喜你，你得到了！<br /><br />&nbsp;&nbsp;&nbsp;&nbsp; 在AJAX技术迅猛发展的今天，许多成功的AJAX项目的JavaScript运行库都大量扩展了内置函数的prototype功能。比如微软的 ASP.NET AJAX，就给这些内置函数及其prototype添加了大量的新特性，从而增强了JavaScript的功能。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;我们来看一段摘自MicrosoftAjax.debug.js中的代码：<br />&nbsp;</p><p>&nbsp;</p><div>String.prototype.trim&nbsp;=&nbsp;function&nbsp;String$trim()&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(arguments.length&nbsp;!==&nbsp;0)&nbsp;throw&nbsp;Error.parameterCount();<br />&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;this.replace(/^\s+|\s+$/g,&nbsp;'');<br />}</div><p>&nbsp;</p><p><br />&nbsp;&nbsp;&nbsp;&nbsp; 这段代码就是给内置String函数的prototype扩展了一个trim方法，于是所有的String类对象都有了trim方法了。有了这个扩展，今后要去除字符串两段的空白，就不用再分别处理了，因为任何字符串都有了这个扩展功能，只要调用即可，真的很方便。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;当然，几乎很少有人去给Object的prototype添加方法，因为那会影响到所有的对象，除非在你的架构中这种方法的确是所有对象都需要的。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;前两年，微软在设计AJAX类库的初期，用了一种被称为&ldquo;闭包&rdquo;(closure)的技术来模拟&ldquo;类&rdquo;。其大致模型如下：</p><p>&nbsp;</p><div>&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;Person(firstName,&nbsp;lastName,&nbsp;age)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//私有变量：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;_firstName&nbsp;=&nbsp;firstName;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;_lastName&nbsp;=&nbsp;lastName;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//公共变量:<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.age&nbsp;=&nbsp;age;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//方法：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.getName&nbsp;=&nbsp;function()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return(firstName&nbsp;+&nbsp;&quot;&nbsp;&quot;&nbsp;+&nbsp;lastName);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.SayHello&nbsp;=&nbsp;function()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(&quot;Hello,&nbsp;I'm&nbsp;&quot;&nbsp;+&nbsp;firstName&nbsp;+&nbsp;&quot;&nbsp;&quot;&nbsp;+&nbsp;lastName);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;BillGates&nbsp;=&nbsp;new&nbsp;Person(&quot;Bill&quot;,&nbsp;&quot;Gates&quot;,&nbsp;53);<br />&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;SteveJobs&nbsp;=&nbsp;new&nbsp;Person(&quot;Steve&quot;,&nbsp;&quot;Jobs&quot;,&nbsp;53);<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;BillGates.SayHello();<br />&nbsp;&nbsp;&nbsp;&nbsp;SteveJobs.SayHello();<br />&nbsp;&nbsp;&nbsp;&nbsp;alert(BillGates.getName()&nbsp;+&nbsp;&quot;&nbsp;&quot;&nbsp;+&nbsp;BillGates.age);<br />&nbsp;&nbsp;&nbsp;&nbsp;alert(BillGates.firstName);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//这里不能访问到私有变量</div><p>&nbsp;</p><p><br />&nbsp;&nbsp;&nbsp;&nbsp;很显然，这种模型的类描述特别象C#语言的描述形式，在一个构造函数里依次定义了私有成员、公共属性和可用的方法，显得非常优雅嘛。特别是&ldquo;闭包&rdquo;机制可以模拟对私有成员的保护机制，做得非常漂亮。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp; 所谓的&ldquo;闭包&rdquo;，就是在构造函数体内定义另外的函数作为目标对象的方法函数，而这个对象的方法函数反过来引用外层外层函数体中的临时变量。这使得只要目标对象在生存期内始终能保持其方法，就能间接保持原构造函数体当时用到的临时变量值。尽管最开始的构造函数调用已经结束，临时变量的名称也都消失了，但在目标对象的方法内却始终能引用到该变量的值，而且该值只能通这种方法来访问。即使再次调用相同的构造函数，但只会生成新对象和方法，新的临时变量只是对应新的值，和上次那次调用的是各自独立的。的确很巧妙！<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;但是前面我们说过，给每一个对象设置一份方法是一种很大的浪费。还有，&ldquo;闭包&rdquo;这种间接保持变量值的机制，往往会给JavaSript的垃圾回收器制造难题。特别是遇到对象间复杂的循环引用时，垃圾回收的判断逻辑非常复杂。无独有偶，IE浏览器早期版本确实存在JavaSript垃圾回收方面的内存泄漏问题。再加上&ldquo;闭包&rdquo;模型在性能测试方面的表现不佳，微软最终放弃了&ldquo;闭包&rdquo; 模型，而改用&ldquo;原型&rdquo;模型。正所谓&ldquo;有得必有失&rdquo;嘛。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;原型模型需要一个构造函数来定义对象的成员，而方法却依附在该构造函数的原型上。大致写法如下：</p><p>&nbsp;</p><div>&nbsp;&nbsp;&nbsp;&nbsp;//定义构造函数<br />&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;Person(name)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.name&nbsp;=&nbsp;name;&nbsp;&nbsp;&nbsp;//在构造函数中定义成员<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;//方法定义到构造函数的prototype上<br />&nbsp;&nbsp;&nbsp;&nbsp;Person.prototype.SayHello&nbsp;=&nbsp;function()<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(&quot;Hello,&nbsp;I'm&nbsp;&quot;&nbsp;+&nbsp;this.name);<br />&nbsp;&nbsp;&nbsp;&nbsp;};&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;//子类构造函数<br />&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;Employee(name,&nbsp;salary)<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Person.call(this,&nbsp;name);&nbsp;&nbsp;&nbsp;&nbsp;//调用上层构造函数<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.salary&nbsp;=&nbsp;salary;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//扩展的成员<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;//子类构造函数首先需要用上层构造函数来建立prototype对象，实现继承的概念<br />&nbsp;&nbsp;&nbsp;&nbsp;Employee.prototype&nbsp;=&nbsp;new&nbsp;Person()&nbsp;&nbsp;&nbsp;//只需要其prototype的方法，此对象的成员没有任何意义！<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;//子类方法也定义到构造函数之上<br />&nbsp;&nbsp;&nbsp;&nbsp;Employee.prototype.ShowMeTheMoney&nbsp;=&nbsp;function()<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(this.name&nbsp;+&nbsp;&quot;&nbsp;$&quot;&nbsp;+&nbsp;this.salary);<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;BillGates&nbsp;=&nbsp;new&nbsp;Person(&quot;Bill&nbsp;Gates&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;BillGates.SayHello();&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;SteveJobs&nbsp;=&nbsp;new&nbsp;Employee(&quot;Steve&nbsp;Jobs&quot;,&nbsp;1234);<br />&nbsp;&nbsp;&nbsp;&nbsp;SteveJobs.SayHello();<br />&nbsp;&nbsp;&nbsp;&nbsp;SteveJobs.ShowMeTheMoney();</div><p>&nbsp;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;原型类模型虽然不能模拟真正的私有变量，而且也要分两部分来定义类，显得不怎么&ldquo;优雅&rdquo;。不过，对象间的方法是共享的，不会遇到垃圾回收问题，而且性能优于&ldquo;闭包&rdquo;模型。正所谓&ldquo;有失必有得&rdquo;嘛。</p><p>&nbsp;&nbsp;&nbsp;&nbsp; 在原型模型中，为了实现类继承，必须首先将子类构造函数的prototype设置为一个父类的对象实例。创建这个父类对象实例的目的就是为了构成原型链，以起到共享上层原型方法作用。但创建这个实例对象时，上层构造函数也会给它设置对象成员，这些对象成员对于继承来说是没有意义的。虽然，我们也没有给构造函数传递参数，但确实创建了若干没有用的成员，尽管其值是undefined，这也是一种浪费啊。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;唉！世界上没有完美的事情啊！<br /><br />原型真谛<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;正当我们感概万分时，天空中一道红光闪过，祥云中出现了观音菩萨。只见她手持玉净瓶，轻拂翠柳枝，洒下几滴甘露，顿时让JavaScript又添新的灵气。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;观音洒下的甘露在JavaScript的世界里凝结成块，成为了一种称为&ldquo;语法甘露&rdquo;的东西。这种语法甘露可以让我们编写的代码看起来更象对象语言。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;要想知道这&ldquo;语法甘露&rdquo;为何物，就请君侧耳细听。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;在理解这些语法甘露之前，我们需要重新再回顾一下JavaScript构造对象的过程。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp; 我们已经知道，用 var anObject = new aFunction() 形式创建对象的过程实际上可以分为三步：第一步是建立一个新对象；第二步将该对象内置的原型对象设置为构造函数prototype引用的那个原型对象；第三步就是将该对象作为this参数调用构造函数，完成成员设置等初始化工作。对象建立之后，对象上的任何访问和操作都只与对象自身及其原型链上的那串对象有关，与构造函数再扯不上关系了。换句话说，构造函数只是在创建对象时起到介绍原型对象和初始化对象两个作用。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;那么，我们能否自己定义一个对象来当作原型，并在这个原型上描述类，然后将这个原型设置给新创建的对象，将其当作对象的类呢？我们又能否将这个原型中的一个方法当作构造函数，去初始化新建的对象呢？例如，我们定义这样一个原型对象：</p><p>&nbsp;</p><div>&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;Person&nbsp;=&nbsp;&nbsp;//定义一个对象来作为原型类<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Create:&nbsp;function(name,&nbsp;age)&nbsp;&nbsp;//这个当构造函数<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.name&nbsp;=&nbsp;name;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.age&nbsp;=&nbsp;age;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SayHello:&nbsp;function()&nbsp;&nbsp;//定义方法<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(&quot;Hello,&nbsp;I'm&nbsp;&quot;&nbsp;+&nbsp;this.name);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HowOld:&nbsp;function()&nbsp;&nbsp;//定义方法<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(this.name&nbsp;+&nbsp;&quot;&nbsp;is&nbsp;&quot;&nbsp;+&nbsp;this.age&nbsp;+&nbsp;&quot;&nbsp;years&nbsp;old.&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;};</div><p>&nbsp;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;这个JSON形式的写法多么象一个C#的类啊！既有构造函数，又有各种方法。如果可以用某种形式来创建对象，并将对象的内置的原型设置为上面这个&ldquo;类&rdquo;对象，不就相当于创建该类的对象了吗？<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;但遗憾的是，我们几乎不能访问到对象内置的原型属性！尽管有些浏览器可以访问到对象的内置原型，但这样做的话就只能限定了用户必须使用那种浏览器。这也几乎不可行。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;那么，我们可不可以通过一个函数对象来做媒介，利用该函数对象的prototype属性来中转这个原型，并用new操作符传递给新建的对象呢？<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;其实，象这样的代码就可以实现这一目标：</p><p>&nbsp;</p><div>&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;anyfunc(){};&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//定义一个函数躯壳<br />&nbsp;&nbsp;&nbsp;&nbsp;anyfunc.prototype&nbsp;=&nbsp;Person;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//将原型对象放到中转站prototype<br />&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;BillGates&nbsp;=&nbsp;new&nbsp;anyfunc();&nbsp;&nbsp;//新建对象的内置原型将是我们期望的原型对象</div><p>&nbsp;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;不过，这个anyfunc函数只是一个躯壳，在使用过这个躯壳之后它就成了多余的东西了，而且这和直接使用构造函数来创建对象也没啥不同，有点不爽。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;可是，如果我们将这些代码写成一个通用函数，而那个函数躯壳也就成了函数内的函数，这个内部函数不就可以在外层函数退出作用域后自动消亡吗？而且，我们可以将原型对象作为通用函数的参数，让通用函数返回创建的对象。我们需要的就是下面这个形式：</p><p>&nbsp;</p><div>&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;New(aClass,&nbsp;aParams)&nbsp;&nbsp;&nbsp;&nbsp;//通用创建函数<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;new_()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//定义临时的中转函数壳<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;aClass.Create.apply(this,&nbsp;aParams);&nbsp;&nbsp;&nbsp;//调用原型中定义的的构造函数，中转构造逻辑及构造参数<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new_.prototype&nbsp;=&nbsp;aClass;&nbsp;&nbsp;&nbsp;&nbsp;//准备中转原型对象<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;new_();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//返回建立最终建立的对象<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;Person&nbsp;=&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//定义的类<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Create:&nbsp;function(name,&nbsp;age)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.name&nbsp;=&nbsp;name;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.age&nbsp;=&nbsp;age;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SayHello:&nbsp;function()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(&quot;Hello,&nbsp;I'm&nbsp;&quot;&nbsp;+&nbsp;this.name);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HowOld:&nbsp;function()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(this.name&nbsp;+&nbsp;&quot;&nbsp;is&nbsp;&quot;&nbsp;+&nbsp;this.age&nbsp;+&nbsp;&quot;&nbsp;years&nbsp;old.&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;BillGates&nbsp;=&nbsp;New(Person,&nbsp;[&quot;Bill&nbsp;Gates&quot;,&nbsp;53]);&nbsp;&nbsp;//调用通用函数创建对象，并以数组形式传递构造参数<br />&nbsp;&nbsp;&nbsp;&nbsp;BillGates.SayHello();<br />&nbsp;&nbsp;&nbsp;&nbsp;BillGates.HowOld();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;alert(BillGates.constructor&nbsp;==&nbsp;Object);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//输出：true</div><p>&nbsp;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;这里的通用函数New()就是一个&ldquo;语法甘露&rdquo;！这个语法甘露不但中转了原型对象，还中转了构造函数逻辑及构造参数。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp; 有趣的是，每次创建完对象退出New函数作用域时，临时的new_函数对象会被自动释放。由于new_的prototype属性被设置为新的原型对象，其原来的原型对象和new_之间就已解开了引用链，临时函数及其原来的原型对象都会被正确回收了。上面代码的最后一句证明，新创建的对象的 constructor属性返回的是Object函数。其实新建的对象自己及其原型里没有constructor属性，那返回的只是最顶层原型对象的构造函数，即Object。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;有了New这个语法甘露，类的定义就很像C#那些静态对象语言的形式了，这样的代码显得多么文静而优雅啊！<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;当然，这个代码仅仅展示了&ldquo;语法甘露&rdquo;的概念。我们还需要多一些的语法甘露，才能实现用简洁而优雅的代码书写类层次及其继承关系。好了，我们再来看一个更丰富的示例吧：</p><p>&nbsp;</p><div>&nbsp;&nbsp;&nbsp;&nbsp;//语法甘露：<br />&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;object&nbsp;=&nbsp;&nbsp;&nbsp;&nbsp;//定义小写的object基本类，用于实现最基础的方法等<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isA:&nbsp;function(aType)&nbsp;&nbsp;&nbsp;//一个判断类与类之间以及对象与类之间关系的基础方法<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;self&nbsp;=&nbsp;this;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(self)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(self&nbsp;==&nbsp;aType)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;true;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self&nbsp;=&nbsp;self.Type;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;false;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;Class(aBaseClass,&nbsp;aClassDefine)&nbsp;&nbsp;&nbsp;&nbsp;//创建类的函数，用于声明类及继承关系<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;class_()&nbsp;&nbsp;&nbsp;//创建类的临时函数壳<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.Type&nbsp;=&nbsp;aBaseClass;&nbsp;&nbsp;&nbsp;&nbsp;//我们给每一个类约定一个Type属性，引用其继承的类<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(var&nbsp;member&nbsp;in&nbsp;aClassDefine)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this[member]&nbsp;=&nbsp;aClassDefine[member];&nbsp;&nbsp;&nbsp;&nbsp;//复制类的全部定义到当前创建的类<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class_.prototype&nbsp;=&nbsp;aBaseClass;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;class_();<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;New(aClass,&nbsp;aParams)&nbsp;&nbsp;&nbsp;//创建对象的函数，用于任意类的对象创建<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;function&nbsp;new_()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//创建对象的临时函数壳<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.Type&nbsp;=&nbsp;aClass;&nbsp;&nbsp;&nbsp;&nbsp;//我们也给每一个对象约定一个Type属性，据此可以访问到对象所属的类<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(aClass.Create)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;aClass.Create.apply(this,&nbsp;aParams);&nbsp;&nbsp;&nbsp;//我们约定所有类的构造函数都叫Create，这和DELPHI比较相似<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;new_.prototype&nbsp;=&nbsp;aClass;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;new&nbsp;new_();<br />&nbsp;&nbsp;&nbsp;&nbsp;};<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;//语法甘露的应用效果：&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;Person&nbsp;=&nbsp;Class(object,&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//派生至object基本类<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Create:&nbsp;function(name,&nbsp;age)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.name&nbsp;=&nbsp;name;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.age&nbsp;=&nbsp;age;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SayHello:&nbsp;function()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(&quot;Hello,&nbsp;I'm&nbsp;&quot;&nbsp;+&nbsp;this.name&nbsp;+&nbsp;&quot;,&nbsp;&quot;&nbsp;+&nbsp;this.age&nbsp;+&nbsp;&quot;&nbsp;years&nbsp;old.&quot;);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;});<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;Employee&nbsp;=&nbsp;Class(Person,&nbsp;&nbsp;&nbsp;&nbsp;//派生至Person类，是不是和一般对象语言很相似？<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Create:&nbsp;function(name,&nbsp;age,&nbsp;salary)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Person.Create.call(this,&nbsp;name,&nbsp;age);&nbsp;&nbsp;//调用基类的构造函数<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.salary&nbsp;=&nbsp;salary;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;},<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ShowMeTheMoney:&nbsp;function()<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;alert(this.name&nbsp;+&nbsp;&quot;&nbsp;$&quot;&nbsp;+&nbsp;this.salary);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;});<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;BillGates&nbsp;=&nbsp;New(Person,&nbsp;[&quot;Bill&nbsp;Gates&quot;,&nbsp;53]);<br />&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;SteveJobs&nbsp;=&nbsp;New(Employee,&nbsp;[&quot;Steve&nbsp;Jobs&quot;,&nbsp;53,&nbsp;1234]);<br />&nbsp;&nbsp;&nbsp;&nbsp;BillGates.SayHello();<br />&nbsp;&nbsp;&nbsp;&nbsp;SteveJobs.SayHello();<br />&nbsp;&nbsp;&nbsp;&nbsp;SteveJobs.ShowMeTheMoney();<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;LittleBill&nbsp;=&nbsp;New(BillGates.Type,&nbsp;[&quot;Little&nbsp;Bill&quot;,&nbsp;6]);&nbsp;&nbsp;&nbsp;//根据BillGate的类型创建LittleBill<br />&nbsp;&nbsp;&nbsp;&nbsp;LittleBill.SayHello();<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;alert(BillGates.isA(Person));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//true<br />&nbsp;&nbsp;&nbsp;&nbsp;alert(BillGates.isA(Employee));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//false<br />&nbsp;&nbsp;&nbsp;&nbsp;alert(SteveJobs.isA(Person));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//true<br />&nbsp;&nbsp;&nbsp;&nbsp;alert(Person.isA(Employee));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//false<br />&nbsp;&nbsp;&nbsp;&nbsp;alert(Employee.isA(Person));&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//true</div><p>&nbsp;</p><p>&nbsp;&nbsp;&nbsp;&nbsp;&ldquo;语法甘露&rdquo;不用太多，只要那么一点点，就能改观整个代码的易读性和流畅性，从而让代码显得更优雅。有了这些语法甘露，JavaScript就很像一般对象语言了，写起代码了感觉也就爽多了！<br /><br />&nbsp;&nbsp;&nbsp;&nbsp; 令人高兴的是，受这些甘露滋养的JavaScript程序效率会更高。因为其原型对象里既没有了毫无用处的那些对象级的成员，而且还不存在 constructor属性体，少了与构造函数间的牵连，但依旧保持了方法的共享性。这让JavaScript在追溯原型链和搜索属性及方法时，少费许多工夫啊。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;我们就把这种形式称为&ldquo;甘露模型&rdquo;吧！其实，这种&ldquo;甘露模型&rdquo;的原型用法才是符合prototype概念的本意，才是的JavaScript原型的真谛！<br /><br />&nbsp;&nbsp;&nbsp;&nbsp; 想必微软那些设计AJAX架构的工程师看到这个甘露模型时，肯定后悔没有早点把AJAX部门从美国搬到咱中国的观音庙来，错过了观音菩萨的点化。当然，我们也只能是在代码的示例中，把Bill Gates当作对象玩玩，真要让他放弃上帝转而皈依我佛肯定是不容易的，机缘未到啊！如果哪天你在微软新出的AJAX类库中看到这种甘露模型，那才是真正的缘分！<br /><br />编程的快乐<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;在软件工业迅猛发展的今天，各式各样的编程语言层出不穷，新语言的诞生，旧语言的演化，似乎已经让我们眼花缭乱。为了适应面向对象编程的潮流，JavaScript语言也在向完全面向对象的方向发展，新的 JavaScript标准已经从语义上扩展了许多面向对象的新元素。与此相反的是，许多静态的对象语言也在向JavaScript的那种简洁而幽雅的方向发展。例如，新版本的C#语言就吸收了JSON那样的简洁表示法，以及一些其他形式的JavaScript特性。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;我们应该看到，随着RIA(强互联应用)的发展和普及，AJAX技术也将逐渐淡出江湖，JavaScript也将最终消失或演化成其他形式的语言。但不管编程语言如何发展和演化，编程世界永远都会在&ldquo;数据&rdquo;与&ldquo;代码&rdquo;这千丝万缕的纠缠中保持着无限的生机。只要我们能看透这一点，我们就能很容易地学习和理解软件世界的各种新事物。不管是已熟悉的过程式编程，还是正在发展的函数式编程，以及未来量子纠缠态的大规模并行式编程，我们都有足够的法力来化解一切复杂的难题。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp; 佛最后淡淡地说：只要我们放下那些表面的&ldquo;类&rdquo;，放下那些对象的&ldquo;自我&rdquo;，就能达到一种&ldquo;对象本无根，类型亦无形&rdquo;的境界，从而将自我融入到整个宇宙的生命轮循环中。我们将没有自我，也没有自私的欲望，你就是我，我就是你，你中有我，我中有你。这时，我们再看这生机勃勃的编程世界时，我们的内心将自然生起无限的慈爱之心，这种慈爱之心不是虚伪而是真诚的。关爱他人就是关爱自己，就是关爱这世界中的一切。那么，我们的心是永远快乐的，我们的程序是永远快乐的，我们的类是永远快乐的，我们的对象也是永远快乐的。这就是编程的极乐！<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;说到这里，在座的比丘都犹如醍醐灌顶，心中豁然开朗。看看左边这位早已喜不自禁，再看看右边那位也是心花怒放。<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;蓦然回首时，唯见君拈花微笑...&nbsp;</p>]]></description><category>程序设计</category><comments>http://www.zhangsan.net/post/118.html#comment</comments><wfw:comment>http://www.zhangsan.net/</wfw:comment><wfw:commentRss>http://www.zhangsan.net/feed.asp?cmt=118</wfw:commentRss><trackback:ping>http://www.zhangsan.net/cmd.asp?act=tb&amp;id=118&amp;key=b97b8352</trackback:ping></item><item><title>使用Writer编写的日志</title><author>a@b.com (liangshan)</author><link>http://www.zhangsan.net/post/117.html</link><pubDate>Wed, 24 Sep 2008 10:39:26 +0800</pubDate><guid>http://www.zhangsan.net/post/117.html</guid><description><![CDATA[<p><a href="http://www.zhangsan.net/upload/%E7%85%A7%E7%89%87001_2.jpg"><img style="border-right: 0px; border-top: 0px; border-left: 0px; border-bottom: 0px" height="184" alt="照片 001" src="http://www.zhangsan.net/upload/%E7%85%A7%E7%89%87001_thumb.jpg" width="244" border="0"></a> </p> <p>这只是一个测试！测试它到底有多智能，有多便利。</p> <p>上图是我的手机</p>]]></description><category>文摘随笔</category><comments>http://www.zhangsan.net/post/117.html#comment</comments><wfw:comment>http://www.zhangsan.net/</wfw:comment><wfw:commentRss>http://www.zhangsan.net/feed.asp?cmt=117</wfw:commentRss><trackback:ping>http://www.zhangsan.net/cmd.asp?act=tb&amp;id=117&amp;key=76e85637</trackback:ping></item><item><title>活车-郑渊洁</title><author>a@b.com (liangshan)</author><link>http://www.zhangsan.net/post/115.html</link><pubDate>Thu, 04 Sep 2008 08:49:20 +0800</pubDate><guid>http://www.zhangsan.net/post/115.html</guid><description><![CDATA[<p>我不信。<br />我不能不信。<br />我的汽车活了。<br />我的那辆牌照号M ７５６２的金羊牌汽车是活车。</p><p>第一章<br />国内开车族没有不知照金羊牌小轿车的。这种轿车外形美观，乘坐舒适。特别令驾驶员青睐的是它的操作系统几乎是完美已无缺的，灵活，可靠，值得信赖。难怪金羊牌轿车的广告是这样说的：金羊牌轿车。坐车的是老板。开车的也是老板。<br />拥有一辆金羊牌轿车是我多年的夙愿。当然，它的价格对于我这样的靠工资吃饭的职员来说，令人望而却步。我不敢奢望自己能够在五十岁前拥有他。<br />每当我在大街上看见金羊牌轿车疾驶而过时，我都会不由自主地驻足观看，一直到他没影为止。这时，我脑海中总是浮现海豚在水中那潇洒的游弋姿态。<br />我从小就喜欢汽车。我上街的最大乐趣就是欣赏各式各样的汽车。我觉得汽车是人类智慧的结晶。每当我看见人类将自然界的矿石、石油、橡胶&hellip;&hellip;糅合在一起然后让它在地球上奔跑时我内心就产生一股不可名状的激情。我庆幸自己投了人胎。<br />作为与人类的一员，在生命的全程中从未驾驶过汽车或从未拥有过一辆汽车，实在是一个天大的遗憾，白白浪费了作为人的特权。动物没这个福气。<br />当今世界的汽车工业竞争激烈。激烈的竞争给我这个经济拮据的车迷带来了曙光。<br />这些上班时，我在报上看到了金羊轿车不惜血本在报上做的整板广告。当我的目光刚一接触到广告标题时，我的心就怦怦急跳起来。广告的标题是：金羊轿车驶入普通职员的家庭下边的小字是：金羊汽车集团推出分期付款购车方式我用左手按住狂跳的心脏，迅速将分期付款的具体数字看了两遍。我拿过办公桌上的计算器，将分期付款购车款项与我的存款数额算了一遍。计算机的显示出上的数字表明，我明天就可以求一辆地道的金羊轿车了！<br />我想拥抱办公室里的所有男同事&mdash;&mdash;包括对头。我想吻办公室里的所有女同事&mdash;&mdash;包括还差１个月就要退休的。<br />下班回家后，我将好消息告诉妻和女儿。他们也同我一样兴奋。受我多年的影响和熏陶，他们喜欢汽车的程度仅次于时装。<br />&ldquo;明天就去买车？&rdquo;妻问。<br />&ldquo;对，我已经向经理请了假。你们也和我一起去，这是咱们家的节日。&rdquo;我边说边从酒柜里拿那瓶存放了十五年的陈酒。<br />&ldquo;爸爸，我明天可以不上学啦？&rdquo;女儿惊讶地问我。<br />&ldquo;当然，我跟你的老师打电话。就说&hellip;&hellip;嗯&hellip;&hellip;就说带你去看牙医。&rdquo;我说。<br />&ldquo;太棒了！我明天可以不上学啦！&rdquo;10岁的女儿一蹦老高，搂着我的脖子往死里亲我。她知道可以少上一天的课居然比买汽车还高兴。这场面要想是让她的班主任看见，班主任因该跳楼。<br />&ldquo;可你没有驾驶执照啊！谁帮咱们把车开回来呢？&rdquo;妻心细，想到了技术性问题。<br />&ldquo;当然是我自己开回来。新车的处女驶怎么能让别人开呢！&rdquo;我打开酒瓶的木塞子，往酒杯里盛酒。<br />&ldquo;你从来没开过汽车啦！&rdquo;妻反对我拿新车冒险。&ldquo;你放心，我就是为汽车降生照人间的，我的血管里流的不是血，是汽油。我从５岁起，每一个星期都要作开汽车的梦。这样算起来，我的驾龄少说也有７～８年了。再说，每当我坐车时，总是尽量坐在驾驶员旁边，观察的动作，我看了几十年，早就看会了。&rdquo;我喝干了杯中的酒。<br />妻点点头。她知道我的这个习惯，但逢坐车，非所驾驶员旁边的那个座位不可。<br />当你要买一件东西又有了买这个东西钱而没买之前，是最幸福的。这晚上，我们将变成了天堂。我做了几十年开汽车的梦，临到买一车前的这个夜晚，什么梦也没做，你说怪不怪？<br />第２天，我携妻以及女儿先到银行取款，然后叫了辆出租车直奔金羊轿车销售中心。<br />办妥了购车的一切手续之后，地位山川南大褂工作服的小伙子将一辆红字的金羊轿车开到我们眼前。<br />&ldquo;这辆车就属于您了，先生。祝贺您！&rdquo;销售中新主任接过小伙子递给他的一串车钥匙，用双手举到我面前。<br />用心花怒放这个词来形容我的心情他不够分量，可我有找不出劲更大的词来。<br />蓝大褂小伙子为我们打开车门。我整整衣服，象是参加一个庄严的仪式。妻和女儿的脸颊上泛这红光，我们坐进这辆属于我们自己的轿车。感觉就是不一样。<br />当我第一次将钥匙插进车琐时，我觉得我接通的不是汽车的电源，而是与接通了一个新的世纪。<br />妻突然有点紧张的注视着我。我明白，她是担心我开不走这辆车。<br />一分钟后，妻释然了。她脸上浮现出那种只有最幸福的女人才会拥有的微笑。<br />我顺利地将我们的汽车看出了销售大厅。现在，它已经汇入了道路上的车水马龙之中。<br />&ldquo;爸爸真是无师自通。&rdquo;女儿恭维我。<br />&ldquo;你爸爸干什么都使自学成才。&rdquo;妻有幽默感。<br />说来也怪，我头一次开车，却有一种和多年不见的老朋友重逢的感觉。一点儿不陌生。<br />&ldquo;开车满，七分技术，三分运气。&rdquo;我对妻和女儿说。<br />妻打开车载收音机，优美的音乐回响在车厢里。汽车在乐曲的伴奏声中疾驰。<br />车窗外一排排后退的商店，树木和行人像一个个巨大的音符，我们的车像一台会奔驰的钢琴，把那些音符洒向人间。<br />当天下午，我们去交通管理部门办理了新车上牌照手续。我们的汽车牌照号是M7562 ，妻说这个数字很吉利，我和女儿亦有同感。<br />我将两副崭新的牌照分别安装在汽车的车头和车尾。<br />&ldquo;咱们去兜兜风？&rdquo;女儿提议。<br />&ldquo;行。你们说去哪儿？&rdquo;我踌躇满志的说。<br />&ldquo;去三峰湖。&rdquo;女儿说。<br />&ldquo;太远了！&rdquo;妻发表意见。<br />&ldquo;有车，不算远。我告诉你们，有了汽车，这座城市就变小了。&rdquo;我驾车上了去三峰湖的路。<br />女儿从后座上搂着我的脖子亲我的后脑勺。<br />&ldquo;咱们家等于有多了一间房子。&rdquo;<br />妻总是出语不凡。我扭头深情的看了看坐在我身边的妻。<br />&ldquo;看车！&rdquo;妻突然大喊一声。<br />我急忙将目光从妻的脸上移到汽车的正前方。天哪，我前面的那辆卡车来了个急刹车。<br />而我却只顾看妻，丝毫没有察觉。<br />我的汽车以高速朝那辆卡车的尾部撞去。粗略估计，再有零点一秒二车将撞在一起。<br />我的脑袋&ldquo;嗡&rdquo;的一下。不得不承认，在紧急的状态下，我还不能熟练的驾驶汽车。我的右脚只是离开了油门踏板，但它并未去踩制动踏板。<br />就在我们都闭上眼睛等着撞车的时候，我们的汽车在距离卡车只有５毫米的地方停住了。<br />妻先睁开眼睛，她不顾一切的搂住我，说：&ldquo;你反应真快！你不愧是世界上最棒的司机！&rdquo;<br />女儿也找出她会的最高量级的赞美词送给我。<br />我的大脑一片空白，只有我最清楚：我根本没去踩制动踏板。车是自己停的。可它怎么会自己停车？<br />自尊心和荣誉感使我接受了妻和女儿的褒奖，我没有将金羊自己停下来的事告诉她们。<br />这天妻和女儿玩的真开心，他们还是头一次乘小轿车外出游玩。<br />至于我，满脑子都是金羊自己会停车的问号？。这件事于常理不同，但我丝毫不怀疑自己的神经系统。我们公司的经理就是因为欣赏我的判断力才每月给我最高奖金的。<br />回家之前，我打开了金羊的发动机盖。<br />&ldquo;车有毛病？&rdquo;妻问。<br />&ldquo;新车，能有什么毛病！我随便看看。&rdquo;我想看看这辆金羊有没有什么与众不同的地方。<br />发动机舱里布满的密密麻麻的线路、管道和机件，就像人得五脏六肺。<br />我那点少得可怜的汽车机械厂时不足以是我判断金羊在什么地方与其它则不一样。<br />我们起程了。<br />妻小声哼着一首流行歌曲。女儿则摇下玻璃窗，任凭风梳理她的一头秀发。<br />开着自己的车，啦着血亲在公路上疾驰，我发现自己是一个真正的男子汉。<br />对名形式的一辆面包车行至距我们的金羊不足５米时，突然越过道路中心的双黄线隔离带，将金羊冲过来！<br />我这次反映一切很快，几乎就在我发现险情的同时，我的右脚就死死踩住的制动踏板。<br />我又错了。这时候急刹车，怎样留在原地等人家做！<br />怪事又发生了。金羊并未停车，而是突然越过双黄线，使入逆行，躲过了那辆面包车，在与面包车后边的正常行驶的汽车相撞前，他又敏捷地回到了属于我们的行车路线上。<br />这一系列的惊险动作只持续了２秒钟。<br />我回过神来，将金羊停在路边。<br />那辆面包车撞在了路边的树上。<br />我下车来，来到面包车旁边，那司机刚从梦中惊醒过来，他驾车睡着了。还好，没有大的伤亡。<br />几个司机走到我眼前，翘起大拇指，称赞我的驾驶技术使世界第一，我接受了他们的表扬，但并不心安理得。因为我清楚，是金羊自己化险为夷的。<br />可这怎么可能？</p><p>第二章<br />我在家里成了英雄。<br />当天晚上，妻和女儿为我摆了庆功宴。女儿还做了一个大花环，套在我脖子上。<br />妻举杯：&ldquo;为了你爸爸的超群绝伦的汽车驾驶技术，干杯！&rdquo;<br />三人一饮而尽。<br />&ldquo;我明天去考驾驶执照。&rdquo;我宣布。<br />妻和女儿愣了。<br />&ldquo;爸爸，你不是说，驾驶执照是给哪些运气不好和没有自信心的司机准备的么？&rdquo;女儿问。<br />妻目光里也全是感叹号。<br />我想及其汽车机械常识。我想研究我的金羊的结构。我想知道它为什么能自行其是。<br />经过了近一个月的学习，在我就要控制不住自己想杀了哪个混蛋教练之前，我终于拿到了驾驶执照。我一点儿也不高兴，我觉得这个塑料本是对我的才能的一种侮辱。<br />现在，我又做的第一件事，就使运用我所学到的汽车机械常识，来剖析和研究金羊。<br />星期日，我准备好工具，穿上特意为擦车买的蓝大褂工作服，打开了金羊的发动机盖。<br />发动机再正常不过了。化油器也不含糊。点火线圈、活化塞、空气滤清器、汽油泵、空调机、电瓶&hellip;&hellip;<br />没有任何与众不同之处。<br />我望着金羊的&ldquo;内脏&rdquo;发呆，它为什么能俩词帮我脱险？它凭的是什么？<br />我决定作一次试验。我要在自己的大脑处以完全清醒和平的状态下判断金羊的所作所为。<br />我从家里抱了２床棉被。<br />&ldquo;你干什么？&rdquo;妻见我抱棉被开车出门，不免心生疑窦。<br />&ldquo;有点儿事。马上就回来。&rdquo;我现在还不想把金羊的事告诉她，怕吓了妻。<br />妻一直在阳台上目送我把棉被塞进汽车的后座，然后驱车了我们的住宅区。<br />我开车物色了一个没人的地方，将棉被堆在汽车前十米的地方，我准备让金羊朝棉被幢上去。我要看看它究竟能不能自己停下来。<br />一切准备工作就绪。<br />我坐进驾驶室，往两个太阳穴上不了不少清凉油，以保障大脑的清醒。我又往嘴里塞了一块薄荷糖，尽可能地使内脏帮助大脑思维。<br />我启动发动机。踩离合器。挂档。加油。松离合器。每一个动作都明白无误，像一加一等于二一样清楚。<br />金羊朝棉被撞去。我加速。<br />金羊就要撞倒棉被了，我没有松油门，它保持原速度朝棉被幢去。<br />我估计金羊能在与棉被相撞的刹那自己停住&mdash;&mdash;不管踩没踩制动踏板。<br />金羊没有停车，它从棉被上轧过去了。<br />就在金羊冲棉被上轧过去的时候，我对自己的神经系统头一次发生了怀疑。<br />难道那两次脱险都是我的下意识动作所导致的？难道与金羊本身根本没有关系？<br />当一个人对自己的判断力发生怀疑时，他离疯已经不远了。<br />判断力是一个人能够自立与宇宙的最重要的素质之一。<br />我的目光落在了我身边转即可把树上。<br />&ldquo;也许它知道棉被是撞不坏汽车的？&rdquo;我产生了这个６岁以上的人类成员都不会产生的推理。<br />用树当障碍试验！<br />我豁出去了。<br />如果不弄个水落石出，我明白自己今生今世将一事无成&mdash;&mdash;一个怀疑自己的判断力不准确的人是无法正确驾驭生命航船驶向人生的彼岸的。和一生相比，几万元的汽车算什么。<br />我将金羊开到距离大树二十米远的地方停好。现在我的表情一定像赴刑场英勇就义的叛逆着。<br />我庄严的系好安全带。俩眼的焦距集中在那斑驳陆离的树干上。<br />金羊朝大树驶去。<br />我让它保持着十公里的时速。<br />金羊就要幢上大树了。<br />再撞树的一瞬间，金羊停住了！<br />我低头一看，发现自己的脚不知什么时候踏在了制动踏板上。<br />是我的脚拒绝大脑的指令自行其是把金羊停下来的。<br />难道那前两次化险为夷也是这样？！<br />我的大脑真的糊涂了？！<br />必须再来一次。否则我真的会发疯。<br />我用绳子将左脚捆在离合器踏板上，将右脚捆在加速踏板上。<br />孤注一掷的试验开始了。<br />金羊朝大树驶去。<br />我的两只脚死死地分别被固定在离合器踏板和加速踏板上。<br />就在金羊要撞上大树的一刹那，我的右脚拚命想挣脱束缚去踩制动踏板。我不能目睹自己心爱的汽车尾大树相撞，我的心里无法承受这种残酷。<br />脚的努力是无效的。我把自己的脚捆的太死了，一点余地也不留。<br />我决望地闭上眼睛，就象等待尖刀插进自己的心脏。<br />金羊停住了。<br />我伸开眼睛，由于车头距树杆级近，我无法判断金羊是撞倒树后停下的还是自己停下的。<br />我用最快的速度解开自己的双脚，然后跳出汽车。<br />我的血液沸腾了，他们像游行的队伍那样迅速在我全身的每一根血管里流动。<br />金羊没有撞上大树！它与树杆之间的距离我一言一根手指也伸不进。<br />真正意义上的双喜临门：<br />１：我确实具备超级判断力。<br />２：我的金羊是活车。<br />不管这种事多么不可思议，但他毕竟是事实。我深知，在这个世界上，什么特殊情况都会发生，什么不合乎逻辑的事都会降临。逻辑只是人们根据已有的知识，为自己观察事物定的框框。他的可靠性是相对的，靠不住才是绝对的。人类发展史就是一部不符合逻辑史。<br />我将棉被塞进汽车，任凭自己情绪狂喜着驱车返家。<br />&hellip;&hellip;&hellip;&hellip;（略一段）（维修中心说车辆正常）<br />在回家的路上，凡是遇上红灯，我一次也没踩过制动踏板，金羊也一次没撞过前边汽车的尾部。<br />地地道道的活车。</p><p>第三章<br />我一进家门，妻就火烧火燎地埋怨我：<br />&ldquo;你去哪儿了？你的经理有急事找你。你快给他回电话！&rdquo;<br />我将手中的棉被递给妻，妻看着棉被上的车轮印，满脸狐疑。<br />经理在电话里说，让我马上跟他飞往B 市，说是一笔大生意要泡汤。经理去谈大生意总爱带着我，以协助他作出正确判断。<br />妻忙着给我收拾行装。女儿嘱咐我一到目的地马上打电话告诉她我下榻的饭店的名称。<br />我还来不及告诉妻和女儿金羊是活车的事，楼下来接我的就拼命按喇叭。<br />&ldquo;一路顺风。&rdquo;妻吻我。<br />&ldquo;一路平安。&rdquo;女儿吻我。<br />晚上飞地B 市，住下后，我马上就给妻和女儿不打电话报平安，当然也没忘了将我的住处的电话号码告诉她们。<br />放下电话，我陪经理出席对方为我们准备的宴会。说是宴会，实际上是讨价还价的战场。<br />美味佳肴、觥筹交错。山珍海味。<br />名牌服装。珍贵首饰。豪华手表。<br />外交辞令。彬彬有礼。风度翩翩。<br />全为着一个东西：钱。<br />实话说，我讨厌这种局面。虚伪。假。<br />&ldquo;请问，您是曾先生吗？一位领班问我。<br />&ldquo;对。&rdquo;我点头。<br />&ldquo;您的电话。&rdquo;领班指指吧台上的电话机。<br />我的电话？谁能知道我在这里？我看看表，已是深夜十一点三十分。<br />&ldquo;喂。&rdquo;我拿起话筒。<br />&ldquo;爸爸！&rdquo;对方在听筒里喊，带着哭腔。是女儿！<br />&ldquo;出什么事了？你慢慢说。&rdquo;我预感到家里出了大事。<br />&ldquo;妈妈她突然晕倒了，我不知道怎么办好，爸爸你快回来！&rdquo;女儿显然慌了。<br />&ldquo;打电话叫救护车。&rdquo;我提醒女儿。<br />&ldquo;我要了，他们说救护车都出去了，半个小时以后才有。可我怕妈妈不行了&hellip;&hellip;&rdquo;女儿大哭起来。<br />&ldquo;&hellip;&hellip;&rdquo;我的脑子嗡的一下。<br />&ldquo;你快回来，爸爸！&rdquo;女儿在电话里哭泣。<br />我突然想到了金羊。<br />&ldquo;你听我说，金羊的车钥匙挂在门后。你找隔壁的奶奶帮助，把妈妈抬到车上，直接上医院。&rdquo;我指挥女儿。<br />&ldquo;爸爸，你怎么了？我又不会开车。&rdquo;女儿还清醒。<br />&ldquo;你别管这些，只要你和妈妈坐进去就行！快，听爸爸的，没错的！&rdquo;我坚信金羊会自己把妻送到医院去的。<br />&ldquo;能行吗？爸爸！&rdquo;女儿还是不信。<br />&ldquo;能行！相信我。快去！到了医院给我打电话。&rdquo;我挂上电话，眼睛发直。<br />&ldquo;出了什么事？&rdquo;经理走过来问。看他的表情，生意谈成了。<br />我告诉他。<br />&ldquo;快坐飞机回去！&rdquo;经理收起笑。<br />&ldquo;明天上午才有航班。&rdquo;我说。<br />一个小时后，我在客房里接到了女儿打来的电话。<br />&ldquo;怎么样？&rdquo;我迫不及待地问。<br />&ldquo;妈妈已经住院了。医生说，幸亏送的及时。&rdquo;女儿的声音柔弱无力。听得出，她已经精疲力尽。<br />&ldquo;妈妈现在怎么样？&rdquo;我问。<br />&ldquo;已经没有危险了。&rdquo;与女儿说。<br />&ldquo;你们怎么去的医院？&rdquo;我又问。<br />一说到这个话题，女儿显然来了精神：<br />&ldquo;太怪了，爸爸！我和妈妈一进金羊，刚关好车门，金羊就自己开了！开的快极了。只用了５分钟就到医院了。爸爸，这是怎么回事？&rdquo;女儿滔滔不绝。我鼻子一酸，眼泪大颗大颗往下掉。是感动的泪。<br />金羊是我们家庭的第４位成员。它是有生命的汽车。<br />第二天，我乘坐的飞机一着陆，我就采用跑百米的速度奔出候机楼大厅，我要找出住车去医院。<br />一个熟悉的身影出现在我的视野里。<br />我不相信。<br />一辆红色的金羊车停在大厅外边。<br />这是巧合。同样的车多了。我告诉自己。<br />直到我看见那M7562 的牌照，我才相信这就是我的金羊。我的眼泪再次夺眶而出。<br />它是自己来接我的。<br />当我走到金羊旁边时，才想起没带车钥匙。<br />车门里的保险按钮&ldquo;啪嗒&rdquo;一声，自己跳了起来。<br />我以后连车钥匙也不用带了！<br />我拉开车门，把皮箱往里一扔，刚关上车门，发动机就自己启动了。<br />我驾驶金羊直奔医院。<br />路上，我没对它说一句感激的话。我清楚，我怎么想，它都知道。<br />在医院的病房里，我们全家举行了一个小小的仪式，我们宣布金羊为我们家庭中的第四位正式成员。<br />妻和女儿的大脑很容易就接受了金羊是活车这个童话般的现实。女人有时的确比男人明智。我不得不承认。<br />妻出院哪天，我把金羊擦的蹭亮！<br />妻在女儿的陪同下走出医院的大楼，来到金羊旁边。她深情的抚摸着金羊的车身。是金羊救了她的命。<br />我驾驶金羊拉着家人绕城一周，以宣泄我们心中的喜悦。</p><p>第四章<br />这天夜里，当我还在梦中时，楼下发生了一件意想不到的事。事后，我知道的事件的详细经过。为了使您一目了然，我从头说起。<br />我居住的这座城市有一个燎汽车的团伙，名曰飞车党。飞车党是本市最令警方头痛的犯罪集团，他们盗窃的汽车累计多达几千辆。警察在飞车党面前显的苍白无力，他们还没抓到过飞车党的一个成员，哪怕是小喽罗。<br />这天夜色降临后，飞车党的几位正式成员盯上了我那停放在楼下的金羊轿车。<br />&ldquo;今天晚上就吃它了。&rdquo;小头目拍板。<br />这几位都是在飞车党内具有高级职称的盗车能手。当夜深人静时，他们开始接近金羊轿车。<br />其中一个掏出一串万能钥匙，他只使用了不到三分中就打开了车门。<br />四个盗车犯蹑手蹑脚的钻进汽车。<br />四个车门&ldquo;啪&rdquo;的一声，全锁死了。<br />&ldquo;怎么回事？&rdquo;小头目往外推门，推不开。<br />&ldquo;谁关的车门？&rdquo;小头目质问。<br />一阵面面相觑。<br />尝试开车门，无效劳动。<br />就在这时，汽车突然启动了，紧接着它使上了公路。<br />&ldquo;你往哪开？&rdquo;小头目问坐在司机位置上的同伙。<br />&ldquo;我没动车！&rdquo;同伙强调。<br />&ldquo;那它怎么走的？&rdquo;小头目火了。<br />同伙举起双手，抬起双脚。以示车动与他无关。<br />汽车飞速行驶。<br />罪犯们拼命砸砸门，砸玻璃，无济于事。<br />金羊拉着４位飞车党成员驶进警察局的大院。<br />&ldquo;这怎么可能？！&rdquo;小头目神经错乱了，他无法接受这个现实。<br />一辆空车硬是把它和兄弟们劫持到了警察局。<br />在大门口站岗的警察跑过来。<br />&ldquo;你们进门怎么不停车？出来！&rdquo;警察的自尊心受挫，他还没间过敢闯警察局的汽车。<br />飞车党成员们出不来。<br />那警察脑子不笨，他觉出蹊跷来了。他跑去喊人。<br />十几名拿着杀伤武器的警察闻讯赶来围住了金羊轿车。<br />一个警察拿手电往车里照。<br />&ldquo;飞车党！&rdquo;不知警察是兴奋还是惊讶，反正他大喊一声。<br />那个小头目的肖像早就在警察局陈列了好几年了。难怪警察一眼就认出了他。<br />围成一圈的警察们平端起冲锋枪。<br />一个警察上去拉车门，车门一拉就开。<br />盗车犯们傻眼了。<br />一阵手铐交响乐。<br />终于抓到了日思夜想的飞车党成员，警察局像过节。局长从被窝里爬出来组织力量突击审讯罪犯。<br />心理攻势加非因心理攻势终于使罪犯们共出了除首犯外的所有同伙&mdash;&mdash;他们确实不知道首犯是谁。<br />数百辆警车出动。<br />数百名飞车党成员被捕。<br />警察局长乐的和不上嘴。<br />&ldquo;对了，怎么抓住哪四个小子的？&rdquo;局长问助手。他准备重奖最先抓住哪四个坏蛋的警察。<br />&ldquo;这事挺怪。他们四个自己坐在一辆金羊轿车里开进局里来的。&rdquo;助手说。<br />&ldquo;自己开进来的？&rdquo;局长瞪大了眼睛。<br />&ldquo;对。&rdquo;助手点头。<br />&ldquo;自首？&rdquo;局长问。<br />&ldquo;不是。&rdquo;助手否定。<br />&ldquo;喝多酒了？&rdquo;局长又问。<br />&ldquo;滴酒未沾。&rdquo;助手又否定。<br />&ldquo;精神错乱？&rdquo;局长再找不出理由了。<br />&ldquo;精神专家鉴定了，四个人都正常。&rdquo;助手枪毙了局长的所有推理。<br />&ldquo;天方夜谭。&rdquo;局长摸后脑勺。&ldquo;走，带我去看看那辆车。&rdquo;<br />局长在助手的陪同下来到院子里。<br />连金羊的影子也没有。<br />&ldquo;那辆金羊呢？&rdquo;局长助手问门卫。<br />&ldquo;刚才还在这儿呢！&rdquo;那警察一看车没了，头上直冒汗。本来他已为自己起码弄个二级勋章戴戴。<br />&ldquo;有生人进来吗？&rdquo;局长严厉地问。<br />&ldquo;没有&hellip;&hellip;&rdquo;警察慌了。<br />&ldquo;你从来没有离开大门？&rdquo;助手问。<br />&ldquo;没有！对了，我刚才接过一次电话。大约也就半分钟吧。&rdquo;警察想起来了。<br />&ldquo;这可怪了。&rdquo;警察局长作推理状。掏香烟。沉思。<br />&ldquo;我把那辆车的车号记下来了。&rdquo;警察突然一拍脑袋，从衣袋里掏出一张纸，递给局长的助手。<br />纸条上写着：Ｍ７５６２。<br />&ldquo;马上查车主。&rdquo;局长吩咐助手。<br />助手跑进局电脑档案室。<br />只用了三分钟，我的名字和电话号码就出现在警察局长办公桌上的荧光屏上。<br />我正在梦中，一阵急促的电话铃声把我惊醒。<br />我打开床头灯，看看表，才四点二十分。&ldquo;谁这么早打电话！&rdquo;我嘟囔着抓起话筒。<br />&ldquo;喂&mdash;&mdash;&rdquo;我迷迷糊糊的问话。<br />&ldquo;请问是曾先生吗？&rdquo;对方说。<br />&ldquo;是。你是谁？&rdquo;我不满地问。骂人的话已经到了嗓子眼，随时可能出膛。<br />&ldquo;我是警察局。请问您是不是有一辆金羊牌汽车？&rdquo;<br />&ldquo;我心头一紧，忙抬头望窗外看。还好，金羊平安无恙的呆在老地方。警察局深更半夜问车，多半与盗车有关。<br />&ldquo;是的。&rdquo;<br />&ldquo;车牌号是多少？&rdquo;<br />&ldquo;Ｍ７５６２。&rdquo;<br />&ldquo;您的车今晚外出吗？&rdquo;<br />&ldquo;没有。&rdquo;<br />&ldquo;现在车在家吗？&rdquo;<br />&ldquo;在。&rdquo;<br />&ldquo;我们想打搅您一下，一会儿去趟您家。&rdquo;<br />&ldquo;为什么？&rdquo;<br />&ldquo;到了再解释吧。&rdquo;<br />电话挂断了。<br />我忙叫醒妻。<br />&ldquo;四点半了，你还想干什么？&rdquo;妻看看表，翻了个身，又要睡。<br />&ldquo;一会儿警察来。&rdquo;我边穿衣服边说。<br />这话真灵，妻马上坐起来。<br />&ldquo;警察？警察来干什么？&rdquo;妻不解的看着我。<br />&ldquo;和金羊有关。&rdquo;我穿好衣服。<br />&ldquo;金羊丢了？&rdquo;妻也往窗外看。<br />&ldquo;金羊好端端的呆在哪儿。也不知深更半夜警察抽什么疯。&rdquo;我准备去洗手间洗把脸。<br />楼下传来汽车和摩托车的引擎声。<br />我趴在窗户上往楼下看，吃了一惊。<br />５辆警车。７辆摩托。<br />来了这么多警察！<br />借着路灯昏暗的光线，我还看见警察手中有非肉体性物体在反光。我仔细一看，身上打了个哆嗦，是枪！<br />&ldquo;好像不对啊！&rdquo;我自言自语。<br />&ldquo;怎么了？&rdquo;妻一边输后一边问。<br />&ldquo;来了好多警察，还拿着枪。&rdquo;我说。<br />&ldquo;都是精神病。甭管他，咱们又没有犯法。&rdquo;妻一甩头发，把梳子重重放在梳妆台上。<br />我看见对面楼上的窗口一个接一个亮了灯，大大小小的头出现在窗台上。<br />敲门声。<br />&ldquo;他们来了。你去女儿的房间，别吓着她。&rdquo;我一边吩咐妻一边去开门。<br />门口站着两位文质彬彬着警察。<br />&ldquo;您是曾先生吗？&rdquo;其中一个戴眼镜的警察问。<br />我点点头。<br />对面的门开了一条缝儿，我粗略计算了一下，那不足十公分门缝儿，从上到下少说也有四双眼睛。<br />&ldquo;对不起，打搅你了。我们可以进去谈吗？&rdquo;另一位不知是有意还是无意把帽子弄成纳粹军帽的英俊警察说。<br />&ldquo;可以问问什么是吗？&rdquo;我要让警察当着对门的四双眼睛说清楚找我的原因，省得他们日后嚼舌头。<br />&ldquo;和您的汽车有关。&rdquo;粹帽说。<br />&ldquo;我的汽车怎么了？&rdquo;我问。<br />&ldquo;还是进屋说吧&rdquo;眼镜警察不想站在楼道里。<br />我只好让他门进屋。当我关上大门后，我听到楼上楼下的邻居们像赶集一样其中到我门口的楼道上。<br />&ldquo;我的车怎么了？&rdquo;不等警察坐下，我就迫不及待的问。语气里包含着明显的不满成分。<br />&ldquo;您今天晚上，噢，对了，是昨天晚上。&rdquo;纳粹帽的时间十分准确，&ldquo;您昨天晚上开车外出吗？&rdquo;<br />&ldquo;没有。&rdquo;我回答。<br />&ldquo;有证人吗？&rdquo;纳粹帽问。<br />我对这句话十分反感。<br />&ldquo;我妻子和女儿。我从下班后一直呆在家里。&rdquo;我的语气开始生硬起来。<br />&ldquo;您的汽车锁了吗？&rdquo;眼镜问。<br />&ldquo;锁了。&rdquo;我说。<br />&ldquo;您几