﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><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>PHP博客-首页</title><link>http://www.phpweblog.net/</link><description /><language>zh-cn</language><lastBuildDate>Thu, 24 Jul 2008 16:20:19 GMT</lastBuildDate><pubDate>Thu, 24 Jul 2008 16:20:19 GMT</pubDate><ttl>60</ttl><item><title>(转) JavaScript面向对象的支持</title><link>http://www.phpweblog.net/fuyongjie/archive/2008/07/23/5449.html</link><dc:creator>bestmost</dc:creator><author>bestmost</author><pubDate>Wed, 23 Jul 2008 10:09:00 GMT</pubDate><guid>http://www.phpweblog.net/fuyongjie/archive/2008/07/23/5449.html</guid><wfw:comment>http://www.phpweblog.net/fuyongjie/comments/5449.html</wfw:comment><comments>http://www.phpweblog.net/fuyongjie/archive/2008/07/23/5449.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.phpweblog.net/fuyongjie/comments/commentRss/5449.html</wfw:commentRss><trackback:ping>http://www.phpweblog.net/fuyongjie/services/trackbacks/5449.html</trackback:ping><description><![CDATA[<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">八、JavaScript面向对象的支持<br></span><span style="color: #000000;">~~~~~~~~~~~~~~~~~~</span><span style="color: #000000;"><br>很少有人对JavaScript的面向对象特性进行系统的分析。我希望接下来的文字让你了解到这<br>个语言最少为人知的一面。<br><br></span><span style="color: #000000;">1</span><span style="color: #000000;">.&nbsp;JavaScript中的类型<br></span><span style="color: #000000;">--------</span><span style="color: #000000;"><br>虽然JavaScript是一个基于对象的语言，但对象(Object)在JavaScript中不是第一型的。JS<br>是以函数(Function)为第一型的语言。这样说，不但是因为JS中的函数具有高级语言中的函<br>数的各种特性，而且也因为在JS中，Object也是由函数来实现的。——关于这一点，可以在<br>后文中&#8220;构造与析构&#8221;部分看到更进一步的说明。<br><br>JS中是弱类型的，他的内置类型简单而且清晰：<br></span><span style="color: #000000;">---------------------------------------------------------</span><span style="color: #000000;"><br>undefined&nbsp;:&nbsp;未定义<br>number&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;数字<br></span><span style="color: #0000ff;">boolean</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;:&nbsp;布尔值<br>string&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;字符串<br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;&nbsp;:&nbsp;函数<br>object&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;对象<br><br></span><span style="color: #000000;">1</span><span style="color: #000000;">).&nbsp;undefined类型<br></span><span style="color: #000000;">========================</span><span style="color: #000000;"><br>在IE5及以下版本中，除了直接赋值和typeof()之外，其它任何对undefined的操作都将导致<br>异常。如果需要知道一个变量是否是undefined，只能采用typeof()的方法：<br></span><span style="color: #000000;">&lt;</span><span style="color: #000000;">script</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;v;<br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">typeof</span><span style="color: #000000;">(v)&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;'undefined')&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;<img src="http://www.phpweblog.net/Images/dot.gif"></span><span style="color: #008000;"><br></span><span style="color: #000000;">}<br></span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">script</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br><br>但是在IE5.5及以上版本中，undefined是一个已实现的系统保留字。因此可以用undefined来<br>比较和运算。检测一个值是否是undefined的更简单方法可以是：<br></span><span style="color: #000000;">&lt;</span><span style="color: #000000;">script</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;v;<br></span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(v&nbsp;</span><span style="color: #000000;">===</span><span style="color: #000000;">&nbsp;undefined)&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;<img src="http://www.phpweblog.net/Images/dot.gif"></span><span style="color: #008000;"><br></span><span style="color: #000000;">}<br></span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">script</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br><br>因此为了使得核心代码能(部分地)兼容IE5及早期版本，Romo核心单元中有一行代码用来<br>&#8220;声明&#8221;一个undefined值：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;code&nbsp;from&nbsp;Qomolangma,&nbsp;in&nbsp;JSEnhance.js</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;undefined&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">;<br><br>这一行代码还有一点是需要说明的，就是void语句的应用。void表明&#8220;执行其后的语句，且<br>忽略返回值&#8221;。因此在void之后可以出现能被执行的任何&#8220;单个&#8221;语句。而执行的结果就是<br>undefined。当然，如果你愿意，你也可以用下面的代码之一&#8220;定义undefined&#8221;。<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;1.&nbsp;较复杂的方法，利用一个匿名的空函数执行的返回</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;undefined&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">function</span><span style="color: #000000;">(){}();<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;2.&nbsp;代码更简洁，但不易懂的方法</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;undefined&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br><br>void也能像函数一样使用，因此void(</span><span style="color: #000000;">0</span><span style="color: #000000;">)也是合法的。有些时候，一些复杂的语句可能不能<br>使用void的关键字形式，而必须要使用void的函数形式。例如：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;必须使用void()形式的复杂表达式</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">void</span><span style="color: #000000;">(i</span><span style="color: #000000;">=</span><span style="color: #000000;">1</span><span style="color: #000000;">);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;或如下语句:</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">void</span><span style="color: #000000;">(i</span><span style="color: #000000;">=</span><span style="color: #000000;">1</span><span style="color: #000000;">,&nbsp;i</span><span style="color: #000000;">++</span><span style="color: #000000;">);<br><br></span><span style="color: #000000;">2</span><span style="color: #000000;">).&nbsp;number类型<br></span><span style="color: #000000;">========================</span><span style="color: #000000;"><br>JavaScript中总是处理浮点数，因此它没有象Delphi中的MaxInt这样的常量，反而是有这<br>样两个常值定义：<br>&nbsp;&nbsp;Number.MAX_VALUE&nbsp;&nbsp;:&nbsp;返回&nbsp;JScript&nbsp;能表达的最大的数。约等于&nbsp;</span><span style="color: #000000;">1.79E+308</span><span style="color: #000000;">。<br>&nbsp;&nbsp;Number.MIN_VALUE&nbsp;&nbsp;:&nbsp;返回&nbsp;JScript&nbsp;最接近0的数。约等于&nbsp;</span><span style="color: #000000;">2.22E-308</span><span style="color: #000000;">。<br><br>因为没有整型的缘故，因此在一些关于CSS和DOM属性的运算中，如果你期望取值为整数2，<br>你可能会得到字符串&#8220;</span><span style="color: #000000;">2.0</span><span style="color: #000000;">&#8221;——或者类似于此的一些情况。这种情况下，你可能需要用<br>到全局对象(Gobal)的parseInt()方法。<br><br>全局对象(Gobal)中还有两个属性与number类型的运算有关：<br>&nbsp;&nbsp;NaN&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;算术表达式的运算结果不是数字，则返回NaN值。<br>&nbsp;&nbsp;Infinity&nbsp;:&nbsp;比MAX_VALUE更大的数。<br><br>如果一个值是NaN，那么他可以通过全局对象(Gobal)的isNaN()方法来检测。然而两个NaN<br>值之间不是互等的。如下例：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;NaN的运算与检测</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;"><br>&nbsp;&nbsp;v1&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">10</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;'a';<br>&nbsp;&nbsp;v2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">10</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;'a';<br>document.writeln(isNaN(v1));<br>document.writeln(isNaN(v2));<br>document.writeln(v1&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;v2);<br><br>全局对象(Gobal)的Infinity表示比最大的数&nbsp;(Number.MAX_VALUE)&nbsp;更大的值。在JS中，<br>它在数学运算时的价值与正无穷是一样的。——在一些实用技巧中，它也可以用来做一<br>个数组序列的边界检测。<br><br>Infinity在Number对象中被定义为POSITIVE_INFINITY。此外，负无穷也在Number中被定<br>义：<br>&nbsp;&nbsp;Number.POSITIVE_INFINITY&nbsp;&nbsp;:&nbsp;比最大正数（Number.MAX_VALUE）更大的值。正无穷。<br>&nbsp;&nbsp;Number.NEGATIVE_INFINITY&nbsp;&nbsp;:&nbsp;比最小负数（</span><span style="color: #000000;">-</span><span style="color: #000000;">Number.MAX_VALUE）更小的值。负无穷。<br><br>与NaN不同的是，两个Infinity(或</span><span style="color: #000000;">-</span><span style="color: #000000;">Infinity)之间是互等的。如下例：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;Infinity的运算与检测</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;"><br>&nbsp;&nbsp;v1&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;Number.MAX_VALUE&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;">;<br>&nbsp;&nbsp;v2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;Number.MAX_VALUE&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">3</span><span style="color: #000000;">;<br>document.writeln(v1);<br>document.writeln(v2);<br>document.writeln(v1&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;v2);<br><br>在Global中其它与number类型相关的方法有：<br>isFinite()&nbsp;&nbsp;&nbsp;:&nbsp;如果值是NaN</span><span style="color: #000000;">/</span><span style="color: #000000;">正无穷</span><span style="color: #000000;">/</span><span style="color: #000000;">负无穷，返回false，否则返回true。<br>parseFloat()&nbsp;:&nbsp;从字符串(的前缀部分)取一个浮点数。不成功则返回NaN。<br><br></span><span style="color: #000000;">3</span><span style="color: #000000;">).&nbsp;boolean类型<br></span><span style="color: #000000;">========================</span><span style="color: #000000;"><br>(略)<br><br></span><span style="color: #000000;">4</span><span style="color: #000000;">).&nbsp;string类型<br></span><span style="color: #000000;">========================</span><span style="color: #000000;"><br>JavaScript中的String类型原本没有什么特殊的，但是JavaScript为了适应<br>&#8220;浏览器实现的超文本环境&#8221;，因此它具有一些奇怪的方法。例如：<br>&nbsp;&nbsp;link()&nbsp;:&nbsp;把一个有HREF属性的超链接标签</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">A</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">放在String对象中的文本两端。<br>&nbsp;&nbsp;big()&nbsp;&nbsp;:&nbsp;把一对</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">big</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">标签放在String对象中的文本两端。<br>以下方法与此类同：<br>&nbsp;&nbsp;anchor()<br>&nbsp;&nbsp;blink()<br>&nbsp;&nbsp;bold()<br>&nbsp;&nbsp;fixed()<br>&nbsp;&nbsp;fontcolor()<br>&nbsp;&nbsp;fontsize()<br>&nbsp;&nbsp;italics()<br>&nbsp;&nbsp;small()<br>&nbsp;&nbsp;strike()<br>&nbsp;&nbsp;sub()<br>&nbsp;&nbsp;sup()<br><br>除此之外，string的主要复杂性来自于在JavaScript中无所不在的toString()<br>方法。这也是JavaScript为浏览器环境而提供的一个很重要的方法。例如我们<br>声明一个对象，但是要用document.writeln()来输出它，在IE中会显示什么呢？<br><br>下例说明这个问题：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;toString()的应用</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;"><br>&nbsp;&nbsp;s&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Object();<br><br>s.v1&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;'hi,';<br>s.v2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;'test</span><span style="color: #000000;">!</span><span style="color: #000000;">';<br>document.writeln(s);<br>document.writeln(s.toString());<br><br>s.toString&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">function</span><span style="color: #000000;">()&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;s.v1&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;s.v2;<br>}<br>document.writeln(s);<br><br>在这个例子中，我们看到，当一个对象没有重新声明(覆盖)自己toString()方<br>法的时候，那么它作为字符串型态使用时(例如被writeln)，就会调用Java&nbsp;Script<br>环境缺省的toString()。反过来，你也可以重新定义JavaScript理解这个对象<br>的方法。<br><br>很多JavaScript框架，在实现&#8220;模板&#8221;机制的时候，就利用了这个特性。例如<br>他们用这样定义一个FontElement对象：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;利用toString()实现模板机制的简单原理</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;FontElement(innerHTML)&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.face&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;'宋体';<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.color&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;'red';<br>&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;more<img src="http://www.phpweblog.net/Images/dot.gif"></span><span style="color: #008000;"><br></span><span style="color: #000000;"><br>&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;ctx&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;innerHTML;<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.toString&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">function</span><span style="color: #000000;">()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;'</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Font&nbsp;FACE</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">'&nbsp;+&nbsp;this.face&nbsp;+&nbsp;'</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;COLOR</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">'&nbsp;+&nbsp;this.color&nbsp;+&nbsp;'</span><span style="color: #000000;">"</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">'<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;ctx<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;'</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">FONT</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">';<br>&nbsp;&nbsp;}<br>}<br><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;obj&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;FontElement('这是一个测试。');<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;留意下面这行代码的写法</span><span style="color: #008000;"><br></span><span style="color: #000000;">document.writeln(obj);<br><br></span><span style="color: #000000;">5</span><span style="color: #000000;">).&nbsp;function类型<br></span><span style="color: #000000;">========================</span><span style="color: #000000;"><br>javascript函数具有很多特性，除了面向对象的部分之外(这在后面讲述)，它自<br>已的一些独特特性应用也很广泛。<br><br>首先javascript中的每个函数，在调用过程中可以执有一个arguments对象。这个<br>对象是由脚本解释环境创建的，你没有别的方法来自己创建一个arguments对象。<br><br>arguments可以看成一个数组：它有length属性，并可以通过arguments[n]的方式<br>来访问每一个参数。然而它最重要的，却是可以通过&nbsp;callee&nbsp;属性来得到正在执行<br>的函数对象的引用。<br><br>接下的问题变得很有趣：Function对象有一个&nbsp;caller&nbsp;属性，指向正在调用当前<br>函数的父函数对象的引用。<br><br>——我们已经看到，我们可以在JavaScript里面，通过callee</span><span style="color: #000000;">/</span><span style="color: #000000;">caller来遍历执行<br>期的调用栈。由于arguments事实上也是Function的一个属性，因此我们事实上也<br>能遍历执行期调用栈上的每一个函数的参数。下面的代码是一个简单的示例：<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;调用栈的遍历</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;foo1(v1,&nbsp;v2)&nbsp;{<br>&nbsp;&nbsp;foo2(v1&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">100</span><span style="color: #000000;">);<br>}<br><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;foo2(v1)&nbsp;{<br>&nbsp;&nbsp;foo3(v1&nbsp;</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">200</span><span style="color: #000000;">);<br>}<br><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;foo3(v1)&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;foo&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;arguments.callee;<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;(foo&nbsp;</span><span style="color: #000000;">&amp;&amp;</span><span style="color: #000000;">&nbsp;(foo&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;window))&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;document.writeln('调用参数：</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">br</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">',&nbsp;'</span><span style="color: #000000;">---------------&lt;</span><span style="color: #000000;">br</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">');<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;args&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;foo.arguments,&nbsp;argn&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;args.length;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;i</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">;&nbsp;i</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">argn;&nbsp;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.writeln('args[',&nbsp;i,&nbsp;']:&nbsp;',&nbsp;args[i],&nbsp;'</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">br</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">');<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;document.writeln('</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">br</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">');<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;上一级</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;foo&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;foo.caller;<br>&nbsp;&nbsp;}<br>}<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;运行测试</span><span style="color: #008000;"><br></span><span style="color: #000000;">foo1(</span><span style="color: #000000;">1</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;">);<br><br></span><span style="color: #000000;">2</span><span style="color: #000000;">.&nbsp;JavaScript面向对象的支持<br></span><span style="color: #000000;">--------</span><span style="color: #000000;"><br>在前面的例子中其实已经讲到了object类型的&#8220;类型声明&#8221;与&#8220;实例创建&#8221;。<br>在JavaScript中，我们需要通过一个函数来声明自己的object类型：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;JavaScript中对象的类型声明的形式代码</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;(以后的文档中，&#8220;对象名&#8221;通常用MyObject来替代)</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;对象名(参数表)&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.属性&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;初始值;<br><br>&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.方法&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">function</span><span style="color: #000000;">(方法参数表)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;方法实现代码</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;}<br>}<br><br>然后，我们可以通过这样的代码来创建这个对象类型的一个实例：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;创建实例的形式代码</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;(以后的文档中，&#8220;实例变量名&#8221;通常用obj来替代)</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;实例变量名&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;对象名(参数表);<br><br>接下来我们来看&#8220;对象&#8221;在JavaScript中的一些具体实现和奇怪特性。<br><br></span><span style="color: #000000;">1</span><span style="color: #000000;">).&nbsp;函数在JavaScript的面向对象机制中的五重身份<br></span><span style="color: #000000;">------</span><span style="color: #000000;"><br>&#8220;对象名&#8221;——如MyObject()——这个函数充当了以下语言角色：<br>&nbsp;&nbsp;(</span><span style="color: #000000;">1</span><span style="color: #000000;">)&nbsp;普通函数<br>&nbsp;&nbsp;(</span><span style="color: #000000;">2</span><span style="color: #000000;">)&nbsp;类型声明<br>&nbsp;&nbsp;(</span><span style="color: #000000;">3</span><span style="color: #000000;">)&nbsp;类型的实现<br>&nbsp;&nbsp;(</span><span style="color: #000000;">4</span><span style="color: #000000;">)&nbsp;类引用<br>&nbsp;&nbsp;(</span><span style="color: #000000;">5</span><span style="color: #000000;">)&nbsp;对象的构造函数<br><br>一些程序员(例如Delphi程序员)习惯于类型声明与实现分开。例如在delphi<br>中，Interface节用于声明类型或者变量，而implementation节用于书写类型<br>的实现代码，或者一些用于执行的函数、代码流程。<br><br>但在JavaScript中，类型的声明与实现是混在一起的。一个对象的类型(类)<br>通过函数来声明，</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.xxxx表明了该对象可具有的属性或者方法。<br><br>这个函数的同时也是&#8220;类引用&#8221;。在JavaScript，如果你需要识别一个对象<br>的具体型别，你需要执有一个&#8220;类引用&#8221;。——当然，也就是这个函数的名<br>字。</span><span style="color: #0000ff;">instanceof</span><span style="color: #000000;">&nbsp;运算符就用于识别实例的类型，我们来看一下它的应用：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;JavaScript中对象的类型识别</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;&nbsp;&nbsp;语法:&nbsp;&nbsp;对象实例&nbsp;instanceof&nbsp;类引用</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;MyObject()&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.data&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;'test&nbsp;data';<br>}<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;这里MyObject()作为构造函数使用</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;obj&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;MyObject();<br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;arr&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Array();<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;这里MyObject作为类引用使用</span><span style="color: #008000;"><br></span><span style="color: #000000;">document.writeln(obj&nbsp;</span><span style="color: #0000ff;">instanceof</span><span style="color: #000000;">&nbsp;MyObject);<br>document.writeln(arr&nbsp;</span><span style="color: #0000ff;">instanceof</span><span style="color: #000000;">&nbsp;MyObject);<br><br></span><span style="color: #000000;">================</span><span style="color: #000000;"><br>(未完待续)<br></span><span style="color: #000000;">================</span><span style="color: #000000;"><br>接下来的内容：<br><br></span><span style="color: #000000;">2</span><span style="color: #000000;">.&nbsp;JavaScript面向对象的支持<br></span><span style="color: #000000;">--------</span><span style="color: #000000;"><br><br></span><span style="color: #000000;">2</span><span style="color: #000000;">).&nbsp;反射机制在JavaScript中的实现<br></span><span style="color: #000000;">3</span><span style="color: #000000;">).&nbsp;this与with关键字的使用<br></span><span style="color: #000000;">4</span><span style="color: #000000;">).&nbsp;使用in关键字的运算<br></span><span style="color: #000000;">5</span><span style="color: #000000;">).&nbsp;使用instanceof关键字的运算<br></span><span style="color: #000000;">6</span><span style="color: #000000;">).&nbsp;其它与面向对象相关的关键字<br><br></span><span style="color: #000000;">3</span><span style="color: #000000;">.&nbsp;构造与析构<br><br></span><span style="color: #000000;">4</span><span style="color: #000000;">.&nbsp;实例和实例引用<br><br></span><span style="color: #000000;">5</span><span style="color: #000000;">.&nbsp;原型问题<br><br></span><span style="color: #000000;">6</span><span style="color: #000000;">.&nbsp;函数的上下文环境<br><br></span><span style="color: #000000;">7</span><span style="color: #000000;">.&nbsp;对象的类型检查问题<br><br></span><span style="color: #000000;">2</span><span style="color: #000000;">).&nbsp;反射机制在JavaScript中的实现<br></span><span style="color: #000000;">------</span><span style="color: #000000;"><br>&nbsp;&nbsp;JavaScript中通过for..in语法来实现了反射机制。但是JavaScript中并不<br>明确区分&#8220;属性&#8221;与&#8220;方法&#8221;，以及&#8220;事件&#8221;。因此，对属性的类型考查在JS<br>中是个问题。下面的代码简单示例for..in的使用与属性识别：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;JavaScript中for..in的使用和属性识别</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;_r_event&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;_r_event&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">/^</span><span style="color: #000000;">[Oo]n.</span><span style="color: #000000;">*/</span><span style="color: #000000;">;<br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;colorSetting&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;{<br>&nbsp;&nbsp;method:&nbsp;'red',<br>&nbsp;&nbsp;event:&nbsp;'blue',<br>&nbsp;&nbsp;property:&nbsp;''<br>}<br><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;obj2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;{<br>&nbsp;&nbsp;a_method&nbsp;:&nbsp;</span><span style="color: #0000ff;">function</span><span style="color: #000000;">()&nbsp;{},<br>&nbsp;&nbsp;a_property:&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">,<br>&nbsp;&nbsp;onclick:&nbsp;undefined<br>}<br><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;propertyKind(obj,&nbsp;p)&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;&nbsp;(_r_event.test(p)&nbsp;</span><span style="color: #000000;">&amp;&amp;</span><span style="color: #000000;">&nbsp;(obj[p]</span><span style="color: #000000;">==</span><span style="color: #000000;">undefined&nbsp;</span><span style="color: #000000;">||</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">typeof</span><span style="color: #000000;">(obj[p])</span><span style="color: #000000;">==</span><span style="color: #000000;">'</span><span style="color: #0000ff;">function</span><span style="color: #000000;">'))&nbsp;</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;'event'<br>&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;(</span><span style="color: #0000ff;">typeof</span><span style="color: #000000;">(obj[p])</span><span style="color: #000000;">==</span><span style="color: #000000;">'</span><span style="color: #0000ff;">function</span><span style="color: #000000;">')&nbsp;</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;'method'<br>&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;'property';<br>}<br><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;objectArr&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;['window',&nbsp;'obj2'];<br><br></span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;i</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">;&nbsp;i</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">objectArr.length;&nbsp;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;document.writeln('</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">p</span><span style="color: #000000;">&gt;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;',&nbsp;objectArr[i],&nbsp;'</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">hr</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">');<br><br>&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;obj&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;eval(objectArr[i]);<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;p&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;obj)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;kind&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;propertyKind(obj,&nbsp;p);<br>&nbsp;&nbsp;&nbsp;&nbsp;document.writeln('obj.',&nbsp;p,&nbsp;'&nbsp;is&nbsp;a&nbsp;',&nbsp;kind.fontcolor(colorSetting[kind]),&nbsp;':&nbsp;',&nbsp;obj[p],&nbsp;'</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">br</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">');<br>&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;document.writeln('</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">p</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">');<br>}<br><br>一个常常被开发者忽略的事实是：JavaScript本身是没有事件(Event)系统的。通<br>常我们在JavaScript用到的onclick等事件，其实是IE的DOM模型提供的。从更内核<br>的角度上讲：IE通过COM的接口属性公布了一组事件接口给DOM。<br><br>有两个原因，使得在JS中不能很好的识别&#8220;一个属性是不是事件&#8221;：<br>&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;COM接口中本身只有方法，属性与事件，都是通过一组get</span><span style="color: #000000;">/</span><span style="color: #000000;">set方法来公布的。<br>&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;JavaScript中，本身并没有独立的&#8220;事件&#8221;机制。<br><br>因此我们看到event的识别方法，是检测属性名是否是以'on'字符串开头(以'On'开<br>头的是Qomo的约定)。接下来，由于DOM对象中的事件是可以不指定处理函数的，这<br>种情况下事件句柄为null值(Qomo采用相同的约定)；在另外的一些情况下，用户可<br>能象obj2这样，定义一个值为&nbsp;undefined的事件。因此&#8220;事件&#8221;的判定条件被处理<br>成一个复杂的表达式：<br>&nbsp;&nbsp;&nbsp;(</span><span style="color: #000000;">"</span><span style="color: #000000;">属性以on/On开头</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&amp;&amp;</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">"</span><span style="color: #000000;">值为null/undefined</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">||</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">类型为function</span><span style="color: #000000;">"</span><span style="color: #000000;">))<br><br>另外，从上面的这段代码的运行结果来看。对DOM对象使用for..</span><span style="color: #0000ff;">in</span><span style="color: #000000;">，是不能列举出<br>对象方法来的。<br><br>最后说明一点。事实上，在很多语言的实现中，&#8220;事件&#8221;都不是&#8220;面向对象&#8221;的语<br>言特性，而是由具体的编程模型来提供的。例如Delphi中的事件驱动机制，是由Win32<br>操作系统中的窗口消息机制来提供，或者由用户代码在Component</span><span style="color: #000000;">/</span><span style="color: #000000;">Class中主动调用<br>事件处理函数来实现。<br><br>&#8220;事件&#8221;是一个&#8220;如何驱动编程模型&#8221;的机制／问题，而不是语言本身的问题。然<br>而以PME(property</span><span style="color: #000000;">/</span><span style="color: #000000;">method</span><span style="color: #000000;">/</span><span style="color: #000000;">event)为框架的OOP概念，已经深入人心，所以当编程语<br>言或系统表现出这些特性来的时候，就已经没人关心&#8220;event究竟是谁实现&#8221;的了。<br><br></span><span style="color: #000000;">3</span><span style="color: #000000;">).&nbsp;this与with关键字的使用<br></span><span style="color: #000000;">------</span><span style="color: #000000;"><br>在JavaScript的对象系统中，this关键字用在两种地方：<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;在构造器函数中，指代新创建的对象实例<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;在对象的方法被调用时，指代调用该方法的对象实例<br><br>如果一个函数被作为普通函数(而不是对象方法)调用，那么在函数中的this关键字<br>将指向window对象。与此相同的，如果this关键字不在任何函数中，那么他也指向<br>window对象。<br><br>由于在JavaScript中不明确区分函数与方法。因此有些代码看起来很奇怪：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;函数的几种可能调用形式</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;foo()&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;下面的this指代调用该方法的对象实例</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">===</span><span style="color: #000000;">window)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;document.write('call&nbsp;a&nbsp;</span><span style="color: #0000ff;">function</span><span style="color: #000000;">.',&nbsp;'</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">BR</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">');<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;document.write('call&nbsp;a&nbsp;method,&nbsp;by&nbsp;object:&nbsp;',&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.name,&nbsp;'</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">BR</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">');<br>&nbsp;&nbsp;}<br>}<br><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;MyObject(name)&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;下面的this指代new关键字新创建实例</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.name&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;name;<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.foo&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;foo;<br>}<br><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;obj1&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;MyObject('obj1');<br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;obj2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;MyObject('obj2');<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;测试1:&nbsp;作为函数调用</span><span style="color: #008000;"><br></span><span style="color: #000000;">foo();<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;测试2:&nbsp;作为对象方法的调用</span><span style="color: #008000;"><br></span><span style="color: #000000;">obj1.foo();<br>obj2.foo();<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;测试3:&nbsp;将函数作为&#8220;指定对象的&#8221;方法调用</span><span style="color: #008000;"><br></span><span style="color: #000000;">foo.call(obj1);<br>foo.apply(obj2);<br><br>在上面的代码里，obj1</span><span style="color: #000000;">/</span><span style="color: #000000;">obj2对foo()的调用是很普通的调用方法。——也就<br>是在构造器上，将一个函数指定为对象的方法。<br><br>而测试3中的call()与apply()就比较特殊。<br><br>在这个测试中，foo()仍然作为普通函数来调用，只是JavaScript的语言特性<br>允许在call()</span><span style="color: #000000;">/</span><span style="color: #000000;">apply()时，传入一个对象实例来指定foo()的上下文环境中所<br>出现的this关键字的引用。——需要注意的是，此时的foo()仍旧是一个普通<br>函数调用，而不是对象方法调用。<br><br>与this&#8220;指示调用该方法的对象实例&#8221;有些类同的，</span><span style="color: #0000ff;">with</span><span style="color: #000000;">()语法也用于限定<br>&#8220;在一段代码片段中默认使用对象实例&#8221;。——如果不使用with()语法，那<br>么这段代码将受到更外层with()语句的影响；如果没有更外层的with()，那<br>么这段代码的&#8220;默认使用的对象实例&#8221;将是window。<br><br>然而需要注意的是this与with关键字不是互为影响的。如下面的代码：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;测试:&nbsp;this与with关键字不是互为影响的</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;test()&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">with</span><span style="color: #000000;">&nbsp;(obj2)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.value&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">8</span><span style="color: #000000;">;<br>&nbsp;&nbsp;}<br>}<br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;obj2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Object();<br>obj2.value&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">10</span><span style="color: #000000;">;<br><br>test();<br>document.writeln('obj2.value:&nbsp;',&nbsp;obj2.value,&nbsp;'</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">br</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">');<br>document.writeln('window.value:&nbsp;',&nbsp;window.value,&nbsp;'</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">br</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">');<br><br>你不能指望这样的代码在调用结束后，会使obj2.value属性置值为8。这几行<br>代码的结果是：window对象多了一个value属性，并且值为8。<br><br></span><span style="color: #0000ff;">with</span><span style="color: #000000;">(obj){<img src="http://www.phpweblog.net/Images/dot.gif">}这个语法，只能限定对obj的既有属性的读取，而不能主动的<br>声明它。一旦with()里的对象没有指定的属性，或者with()限定了一个不是对<br>象的数据，那么结果会产生一个异常。<br><br></span><span style="color: #000000;">4</span><span style="color: #000000;">).&nbsp;使用in关键字的运算<br></span><span style="color: #000000;">------</span><span style="color: #000000;"><br>除了用for..in来反射对象的成员信息之外，JavaScript中也允许直接用in<br>关键字去检测对象是否有指定名字的属性。<br><br>in关键字经常被提及的原因并不是它检测属性是否存在的能力，因此在早期<br>的代码中，很多可喜欢用&#8220;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #000000;">!</span><span style="color: #000000;">obj.propName)&nbsp;{}&#8221;&nbsp;这样的方式来检测propName<br>是否是有效的属性。——很多时候，检测有效性比检测&#8220;是否存有该属性&#8221;更<br>有实用性。因此这种情况下，in只是一个可选的、官方的方案。<br><br>in关键字的重要应用是高速字符串检索。尤其是在只需要判定&#8220;字符串是否<br>存在&#8221;的情况下。例如10万个字符串，如果存储在数组中，那么检索效率将会<br>极差。<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;使用对象来检索</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;arrayToObject(arr)&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;obj</span><span style="color: #000000;">=</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Object(),&nbsp;i</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">,&nbsp;imax</span><span style="color: #000000;">=</span><span style="color: #000000;">arr.length;&nbsp;i</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">imax;&nbsp;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;obj[arr[i]]</span><span style="color: #000000;">=</span><span style="color: #0000ff;">null</span><span style="color: #000000;">;<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;obj;<br>}<br><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;"><br>&nbsp;&nbsp;arr&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;['abc',&nbsp;'def',&nbsp;'ghi'];&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;more&nbsp;and&nbsp;more<img src="http://www.phpweblog.net/Images/dot.gif"></span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;obj&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;arrayToObject(arr);<br><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;valueInArray(v)&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;i</span><span style="color: #000000;">=</span><span style="color: #000000;">0</span><span style="color: #000000;">,&nbsp;imax</span><span style="color: #000000;">=</span><span style="color: #000000;">arr.length;&nbsp;i</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">imax;&nbsp;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(arr[i]</span><span style="color: #000000;">==</span><span style="color: #000000;">v)&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">true</span><span style="color: #000000;">;<br>&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;">;<br>}<br><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;valueInObject(v)&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;v&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;obj;<br>}<br><br>这种使用关键字in的方法，也存在一些限制。例如只能查找字符串，而数<br>组元素可以是任意值。另外，arrayToObject()也存在一些开销，这使得它<br>不适合于频繁变动的查找集。最后，(我想你可能已经注意到了)使用对象<br>来查找的时候并不能准确定位到查找数据，而数组中可以指向结果的下标。<br><br>八、JavaScript面向对象的支持<br></span><span style="color: #000000;">~~~~~~~~~~~~~~~~~~</span><span style="color: #000000;"><br>(续)<br><br></span><span style="color: #000000;">2</span><span style="color: #000000;">.&nbsp;JavaScript面向对象的支持<br></span><span style="color: #000000;">--------</span><span style="color: #000000;"><br>(续)<br><br></span><span style="color: #000000;">5</span><span style="color: #000000;">).&nbsp;使用instanceof关键字的运算<br></span><span style="color: #000000;">------</span><span style="color: #000000;"><br>在JavaScript中提供了instanceof关键字来检测实例的类型。这在前面讨<br>论它的&#8220;五重身份&#8221;时已经讲过。但instanceof的问题是，它总是列举整个<br>原型链以检测类型(关于原型继承的原理在&#8220;构造与析构&#8221;小节讲述)，如：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;instanceof使用中的问题</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;MyObject()&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;<img src="http://www.phpweblog.net/Images/dot.gif"></span><span style="color: #008000;"><br></span><span style="color: #000000;">}<br><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;MyObject2()&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;<img src="http://www.phpweblog.net/Images/dot.gif"></span><span style="color: #008000;"><br></span><span style="color: #000000;">}<br>MyObject2.prototype&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;MyObject();<br><br>obj1&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;MyObject();<br>obj2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;MyObject2();<br><br>document.writeln(obj1&nbsp;</span><span style="color: #0000ff;">instanceof</span><span style="color: #000000;">&nbsp;MyObject,&nbsp;'</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">BR</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">');<br>document.writeln(obj2&nbsp;</span><span style="color: #0000ff;">instanceof</span><span style="color: #000000;">&nbsp;MyObject,&nbsp;'</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">BR</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">');<br><br>我们看到，obj1与obj2都是MyObject的实例，但他们是不同的构造函数产生<br>的。——注意，这在面向对象理论中正确的：因为obj2是MyObject的子类实<br>例，因此它具有与obj1相同的特性。在应用中这是obj2的多态性的体现之一。<br><br>但是，即便如此，我们也必须面临这样的问题：如何知道obj2与obj1是否是<br>相同类型的实例呢？——也就是说，连构造器都相同？<br><br>instanceof关键字不提供这样的机制。一个提供实现这种检测的能力的，是<br>Object.constructor属性。——但请先记住，它的使用远比你想象的要难。<br><br>好的，问题先到这里。constructor属性已经涉及到&#8220;构造与析构&#8221;的问题，<br>这个我们后面再讲。&#8220;原型继承&#8221;、&#8220;构造与析构&#8221;是JavaScript的OOP中<br>的主要问题、核心问题，以及&#8220;致命问题&#8221;。<br><br></span><span style="color: #000000;">6</span><span style="color: #000000;">).&nbsp;null与undefined<br></span><span style="color: #000000;">------</span><span style="color: #000000;"><br>在JavaScript中，null与undefined曾一度使我迷惑。下面的文字，有利于<br>你更清晰的认知它(或者让你更迷惑)：<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;null是关键字；undefined是Global对象的一个属性。<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;null是对象(空对象,&nbsp;没有任何属性和方法)；undefined是undefined类<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;型的值。试试下面的代码：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.writeln(</span><span style="color: #0000ff;">typeof</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.writeln(</span><span style="color: #0000ff;">typeof</span><span style="color: #000000;">&nbsp;undefined);<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;对象模型中，所有的对象都是Object或其子类的实例，但null对象例外：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.writeln(</span><span style="color: #0000ff;">null</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">instanceof</span><span style="color: #000000;">&nbsp;Object);<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">&#8220;等值(</span><span style="color: #000000;">==</span><span style="color: #000000;">)&#8221;于undefined，但不&#8220;全等值(</span><span style="color: #000000;">===</span><span style="color: #000000;">)&#8221;于undefined：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.writeln(</span><span style="color: #0000ff;">null</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;undefined);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.writeln(</span><span style="color: #0000ff;">null</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;undefined);<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;运算时null与undefined都可以被类型转换为false，但不等值于false：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.writeln(</span><span style="color: #000000;">!</span><span style="color: #0000ff;">null</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">!</span><span style="color: #000000;">undefined);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.writeln(</span><span style="color: #0000ff;">null</span><span style="color: #000000;">==</span><span style="color: #0000ff;">false</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;document.writeln(undefined</span><span style="color: #000000;">==</span><span style="color: #0000ff;">false</span><span style="color: #000000;">);<br><br>八、JavaScript面向对象的支持<br></span><span style="color: #000000;">~~~~~~~~~~~~~~~~~~</span><span style="color: #000000;"><br>(续)<br><br></span><span style="color: #000000;">3</span><span style="color: #000000;">.&nbsp;构造、析构与原型问题<br></span><span style="color: #000000;">--------</span><span style="color: #000000;"><br>我们已经知道一个对象是需要通过构造器函数来产生的。我们先记住几点：<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;构造器是一个普通的函数<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;原型是一个对象实例<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;构造器有原型属性，对象实例没有<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;(如果正常地实现继承模型，)对象实例的constructor属性指向构造器<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;从三、四条推出：obj.constructor.prototype指向该对象的原型<br><br>好，我们接下来分析一个例子，来说明JavaScript的&#8220;继承原型&#8221;声明，以<br>及构造过程。<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;理解原型、构造、继承的示例</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;MyObject()&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.v1&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;'abc';<br>}<br><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;MyObject2()&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.v2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;'def';<br>}<br>MyObject2.prototype&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;MyObject();<br><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;obj1&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;MyObject();<br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;obj2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;MyObject2();<br><br></span><span style="color: #000000;">1</span><span style="color: #000000;">).&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">()关键字的形式化代码<br></span><span style="color: #000000;">------</span><span style="color: #000000;"><br>我们先来看&#8220;obj1&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;MyObject()&#8221;这行代码中的这个new关键字。<br><br>new关键字用于产生一个新的实例（说到这里补充一下，我习惯于把保留字叫关键<br>字。另外，在JavaScript中new关键字同时也是一个运算符），这个实例的缺省属性<br>中，(至少)会执有构造器函数的原型属性(prototype)的一个引用(在ECMA&nbsp;Javascript<br>规范中，对象的这个属性名定义为__proto__)。<br><br>每一个函数，无论它是否用作构造器，都会有一个独一无二的原型对象(prototype)。<br>对于JavaScript&#8220;内置对象的构造器&#8221;来说，它指向内部的一个原型。缺省时JavaScript<br>构造出一个&#8220;空的初始对象实例(不是null)&#8221;并使原型引用指向它。然而如果你给函<br>数的这个prototype赋一个新的对象，那么新的对象实例将执有它的一个引用。<br><br>接下来，构造过程将调用MyObject()来完成初始化。——注意，这里只是&#8220;初始<br>化&#8221;。<br><br>为了清楚地解释这个过程，我用代码形式化地描述一下这个过程：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;new()关键字的形式化代码</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">(aFunction)&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;基本对象实例</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;_this&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;{};<br><br>&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;原型引用</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;_proto</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;aFunction.prototype;<br><br></span><span style="color: #008000;">/*</span><span style="color: #008000;">&nbsp;if&nbsp;compat&nbsp;ECMA&nbsp;Script<br>&nbsp;&nbsp;_this.__proto__&nbsp;=&nbsp;_proto;<br></span><span style="color: #008000;">*/</span><span style="color: #000000;"><br><br>&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;为存取原型中的属性添加(内部的)getter</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;_this._js_GetAttributes</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">function</span><span style="color: #000000;">(name)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(_existAttribute.call(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">,&nbsp;name))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">[name]<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(_js_LookupProperty.call(_proto,&nbsp;name))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;retrun&nbsp;OBJ_GET_ATTRIBUTES.call(_proto,&nbsp;name)<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;undefined;<br>&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;为存取原型中的属性添加(内部的)setter</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;_this._js_GetAttributes&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">function</span><span style="color: #000000;">(name,&nbsp;value)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(_existAttribute.call(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">,&nbsp;name))<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">[name]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;value<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(OBJ_GET_ATTRIBUTES.call(_proto,&nbsp;name)&nbsp;</span><span style="color: #000000;">!==</span><span style="color: #000000;">&nbsp;value)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">[name]&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;value&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;创建当前实例的新成员</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;调用构造函数完成初始化,&nbsp;(如果有,)传入args</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;aFunction.call(_this);<br><br>&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;返回对象</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;_this;<br>}<br><br>所以我们看到以下两点：<br>&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;构造函数(aFunction)本身只是对传入的this实例做&#8220;初始化&#8221;处理，而<br>&nbsp;&nbsp;&nbsp;&nbsp;不是构造一个对象实例。<br>&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;构造的过程实际发生在new()关键字</span><span style="color: #000000;">/</span><span style="color: #000000;">运算符的内部。<br><br>而且，构造函数(aFunction)本身并不需要操作prototype，也不需要回传this。<br><br></span><span style="color: #000000;">2</span><span style="color: #000000;">).&nbsp;由用户代码维护的原型(prototype)链<br></span><span style="color: #000000;">------</span><span style="color: #000000;"><br>接下来我们更深入的讨论原型链与构造过程的问题。这就是：<br>&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;原型链是用户代码创建的，</span><span style="color: #0000ff;">new</span><span style="color: #000000;">()关键字并不协助维护原型链<br><br>以Delphi代码为例，我们在声明继承关系的时候，可以用这样的代码：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;delphi中使用的&#8220;类&#8221;类型声明</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #000000;">type<br>&nbsp;&nbsp;TAnimal&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;class(TObject);&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;动物</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;TMammal&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;class(TAnimal);&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;哺乳动物</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;TCanine&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;class(TMammal);&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;犬科的哺乳动物</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;TDog&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;class(TCanine);&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;狗</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br>这时，Delphi的编译器会通过编译技术来维护一个继承关系链表。我们可以通<br>过类似以下的代码来查询这个链表：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;delphi中使用继关系链表的关键代码</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;isAnimal(obj:&nbsp;TObject):&nbsp;</span><span style="color: #0000ff;">boolean</span><span style="color: #000000;">;<br>begin<br>&nbsp;&nbsp;Result&nbsp;:</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;obj&nbsp;is&nbsp;TAnimal;<br>end;<br><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;"><br>&nbsp;&nbsp;dog&nbsp;:</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;TDog;<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;<img src="http://www.phpweblog.net/Images/dot.gif"></span><span style="color: #008000;"><br></span><span style="color: #000000;">dog&nbsp;:</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;TDog.Create();<br>writeln(isAnimal(dog));<br><br>可以看到，在Delphi的用户代码中，不需要直接继护继承关系的链表。这是因<br>为Delphi是强类型语言，在处理用class()关键字声明类型时，delphi的编译器<br>已经为用户构造了这个继承关系链。——注意，这个过程是声明，而不是执行<br>代码。<br><br>而在JavaScript中，如果需要获知对象&#8220;是否是某个基类的子类对象&#8221;，那么<br>你需要手工的来维护(与delphi这个例子类似的)一个链表。当然，这个链表不<br>叫类型继承树，而叫&#8220;(对象的)原型链表&#8221;。——在JS中，没有&#8220;类&#8221;类型。<br><br>参考前面的JS和Delphi代码，一个类同的例子是这样：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;JS中&#8220;原型链表&#8221;的关键代码</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;1.&nbsp;构造器</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;Animal()&nbsp;{};<br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;Mammal()&nbsp;{};<br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;Canine()&nbsp;{};<br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;Dog()&nbsp;{};<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;2.&nbsp;原型链表</span><span style="color: #008000;"><br></span><span style="color: #000000;">Mammal.prototype&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Animal();<br>Canine.prototype&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Mammal();<br>Dog.prototype&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Canine();<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;3.&nbsp;示例函数</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;isAnimal(obj)&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;obj&nbsp;</span><span style="color: #0000ff;">instanceof</span><span style="color: #000000;">&nbsp;Animal;<br>}<br><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;"><br>&nbsp;&nbsp;dog&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Dog();<br>document.writeln(isAnimal(dog));<br><br>可以看到，在JS的用户代码中，&#8220;原型链表&#8221;的构建方法是一行代码：<br>&nbsp;&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">当前类的构造器函数</span><span style="color: #000000;">"</span><span style="color: #000000;">.prototype&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">直接父类的实例</span><span style="color: #000000;">"</span><span style="color: #000000;"><br><br>这与Delphi一类的语言不同：维护原型链的实质是在执行代码，而非声明。<br><br>那么，&#8220;是执行而非声明&#8221;到底有什么意义呢？<br><br>JavaScript是会有编译过程的。这个过程主要处理的是&#8220;语法检错&#8221;、&#8220;语<br>法声明&#8221;和&#8220;条件编译指令&#8221;。而这里的&#8220;语法声明&#8221;，主要处理的就是函<br>数声明。——这也是我说&#8220;函数是第一类的，而对象不是&#8221;的一个原因。<br><br>如下例：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;函数声明与执行语句的关系(firefox&nbsp;兼容)</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;1.&nbsp;输出1234</span><span style="color: #008000;"><br></span><span style="color: #000000;">testFoo(</span><span style="color: #000000;">1234</span><span style="color: #000000;">);<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;2.&nbsp;尝试输出obj1</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;3.&nbsp;尝试输出obj2</span><span style="color: #008000;"><br></span><span style="color: #000000;">testFoo(obj1);<br></span><span style="color: #0000ff;">try</span><span style="color: #000000;">&nbsp;{<br>&nbsp;&nbsp;testFoo(obj2);<br>}<br></span><span style="color: #0000ff;">catch</span><span style="color: #000000;">(e)&nbsp;{<br>&nbsp;&nbsp;document.writeln('Exception:&nbsp;',&nbsp;e.description,&nbsp;'</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">BR</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">');<br>}<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;声明testFoo()</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;testFoo(v)&nbsp;{<br>&nbsp;&nbsp;document.writeln(v,&nbsp;'</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">BR</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">');<br>}<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;&nbsp;声明object</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;obj1&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;{};<br>obj2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;{<br>&nbsp;&nbsp;toString:&nbsp;</span><span style="color: #0000ff;">function</span><span style="color: #000000;">()&nbsp;{</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;'hi,&nbsp;object.'}<br>}<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;4.&nbsp;输出obj1</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;5.&nbsp;输出obj2</span><span style="color: #008000;"><br></span><span style="color: #000000;">testFoo(obj1);<br>testFoo(obj2);<br><br>这个示例代码在JS环境中执行的结果是：<br></span><span style="color: #000000;">------------------------------------</span><span style="color: #000000;"><br>&nbsp;&nbsp;</span><span style="color: #000000;">1234</span><span style="color: #000000;"><br>&nbsp;&nbsp;undefined<br>&nbsp;&nbsp;Exception:&nbsp;'obj2'&nbsp;未定义<br>&nbsp;&nbsp;[object&nbsp;Object]<br>&nbsp;&nbsp;hi,&nbsp;obj<br></span><span style="color: #000000;">------------------------------------</span><span style="color: #000000;"><br>问题是，testFoo()是在它被声明之前被执行的；而同样用&#8220;直接声明&#8221;的<br>形式定义的object变量，却不能在声明之前引用。——例子中，第二、三<br>个输入是不正确的。<br><br>函数可以在声明之前引用，而其它类型的数值必须在声明之后才能被使用。<br>这说明&#8220;声明&#8221;与&#8220;执行期引用&#8221;在JavaScript中是两个过程。<br><br>另外我们也可以发现，使用</span><span style="color: #000000;">"</span><span style="color: #000000;">var</span><span style="color: #000000;">"</span><span style="color: #000000;">来声明的时候，编译器会先确认有该变量<br>存在，但变量的值会是&#8220;undefined&#8221;。——因此&#8220;testFoo(obj1)&#8221;不会发<br>生异常。但是，只有等到关于obj1的赋值语句被执行过，才会有正常的输出。<br>请对照第二、三与第四、五行输出的差异。<br><br>由于JavaScript对原型链的维护是&#8220;执行&#8221;而不是&#8220;声明&#8221;，这说明&#8220;原型<br>链是由用户代码来维护的，而不是编译器维护的。<br><br>由这个推论，我们来看下面这个例子：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;示例：错误的原型链</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;1.&nbsp;构造器</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;Animal()&nbsp;{};&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;动物</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;Mammal()&nbsp;{};&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;哺乳动物</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;Canine()&nbsp;{};&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;犬科的哺乳动物</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;2.&nbsp;构造原型链</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;instance&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Mammal();<br>Mammal.prototype&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Animal();<br>Canine.prototype&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;instance;<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;3.&nbsp;测试输出</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;obj&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Canine();<br>document.writeln(obj&nbsp;</span><span style="color: #0000ff;">instanceof</span><span style="color: #000000;">&nbsp;Animal);<br><br>这个输出结果，使我们看到一个错误的原型链导致的结果&#8220;犬科的哺乳动<br>物&#8216;不是&#8217;一种动物&#8221;。<br><br>根源在于&#8220;</span><span style="color: #000000;">2</span><span style="color: #000000;">.&nbsp;构造原型链&#8221;下面的几行代码是解释执行的，而不是象var和<br>function那样是&#8220;声明&#8221;并在编译期被理解的。解决问题的方法是修改那三<br>行代码，使得它的&#8220;执行过程&#8221;符合逻辑：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;上例的修正代码(部分)</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;2.&nbsp;构造原型链</span><span style="color: #008000;"><br></span><span style="color: #000000;">Mammal.prototype&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Animal();<br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;instance&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Mammal();<br>Canine.prototype&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;instance;<br><br></span><span style="color: #000000;">3</span><span style="color: #000000;">).&nbsp;原型实例是如何被构造过程使用的<br></span><span style="color: #000000;">------</span><span style="color: #000000;"><br>仍以Delphi为例。构造过程中，delphi中会首先创建一个指定实例大小的<br>&#8220;空的对象&#8221;，然后逐一给属性赋值，以及调用构造过程中的方法、触发事<br>件等。<br><br>JavaScript中的new()关键字中隐含的构造过程，与Delphi的构造过程并不完全一致。但<br>在构造器函数中发生的行为却与上述的类似：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;JS中的构造过程(形式代码)</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;MyObject2()&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.prop&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">3</span><span style="color: #000000;">;<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.method&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;a_method_function;<br><br>&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(you_want)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.method();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.fire_OnCreate();<br>&nbsp;&nbsp;}<br>}<br>MyObject2.prototype&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;MyObject();&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;MyObject()的声明略</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;obj&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;MyObject2();<br><br>如果以单个类为参考对象的，这个构造过程中JavaScript可以拥有与Delphi<br>一样丰富的行为。然而，由于Delphi中的构造过程是&#8220;动态的&#8221;，因此事实上<br>Delphi还会调用父类(MyObject)的构造过程，以及触发父类的OnCreate()事件。<br><br>JavaScript没有这样的特性。父类的构造过程仅仅发生在为原型(prototype<br>属性)赋值的那一行代码上。其后，无论有多少个new&nbsp;MyObject2()发生，<br>MyObject()这个构造器都不会被使用。——这也意味着：<br>&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;构造过程中，原型对象是一次性生成的；新对象只持有这个原型实例的引用<br>&nbsp;&nbsp;&nbsp;&nbsp;(并用&#8220;写复制&#8221;的机制来存取其属性)，而并不再调用原型的构造器。<br><br>由于不再调用父类的构造器，因此Delphi中的一些特性无法在JavaScript中实现。<br>这主要影响到构造阶段的一些事件和行为。——无法把一些&#8220;对象构造过程中&#8221;<br>的代码写到父类的构造器中。因为无论子类构造多少次，这次对象的构造过程根<br>本不会激活父类构造器中的代码。<br><br>JavaScript中属性的存取是动态的，因为对象存取父类属性依赖于原型链表，构造<br>过程却是静态的，并不访问父类的构造器；而在Delphi等一些编译型语言中，(不使<br>用读写器的)属性的存取是静态的，而对象的构造过程则动态地调用父类的构造函数。<br>所以再一次请大家看清楚new()关键字的形式代码中的这一行：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;new()关键字的形式化代码</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">(aFunction)&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;原型引用</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;_proto</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;aFunction.prototype;<br><br>&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;<img src="http://www.phpweblog.net/Images/dot.gif"></span><span style="color: #008000;"><br></span><span style="color: #000000;">}<br><br>这个过程中，JavaScript做的是&#8220;get&nbsp;a&nbsp;prototype_Ref&#8221;，而Delphi等其它语言做<br>的是&#8220;Inherited&nbsp;Create()&#8221;。<br><br>八、JavaScript面向对象的支持<br></span><span style="color: #000000;">~~~~~~~~~~~~~~~~~~</span><span style="color: #000000;"><br>(续)<br><br></span><span style="color: #000000;">4</span><span style="color: #000000;">).&nbsp;需要用户维护的另一个属性：constructor<br></span><span style="color: #000000;">------</span><span style="color: #000000;"><br>回顾前面的内容，我们提到过：<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;(如果正常地实现继承模型，)对象实例的constructor属性指向构造器<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;obj.constructor.prototype指向该对象的原型<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;通过Object.constructor属性，可以检测obj2与obj1是否是相同类型的实例<br><br>&nbsp;&nbsp;与原型链要通过用户代码来维护prototype属性一样，实例的构造器属性constructor<br>也需要用户代码维护。<br><br>&nbsp;&nbsp;对于JavaScript的内置对象来说，constructor属性指向内置的构造器函数。如：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;内置对象实例的constructor属性</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;_object_types&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;{<br>&nbsp;&nbsp;'</span><span style="color: #0000ff;">function</span><span style="color: #000000;">'&nbsp;&nbsp;:&nbsp;Function,<br>&nbsp;&nbsp;'</span><span style="color: #0000ff;">boolean</span><span style="color: #000000;">'&nbsp;&nbsp;&nbsp;:&nbsp;Boolean,<br>&nbsp;&nbsp;'regexp'&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;RegExp,<br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;'math'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;Math,</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;'debug'&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;Debug,</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;'image'&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;Image;</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;'undef'&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;undefined,</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;'dom'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;undefined,</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;'activex'&nbsp;&nbsp;:&nbsp;undefined,</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;'vbarray'&nbsp;&nbsp;&nbsp;:&nbsp;VBArray,<br>&nbsp;&nbsp;'array'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;Array,<br>&nbsp;&nbsp;'string'&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;String,<br>&nbsp;&nbsp;'date'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;Date,<br>&nbsp;&nbsp;'error'&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;Error,<br>&nbsp;&nbsp;'enumerator':&nbsp;Enumerator,<br>&nbsp;&nbsp;'number'&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;Number,<br>&nbsp;&nbsp;'object'&nbsp;&nbsp;&nbsp;&nbsp;:&nbsp;Object<br>}<br><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;objectTypes(obj)&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">typeof</span><span style="color: #000000;">&nbsp;obj&nbsp;</span><span style="color: #000000;">!==</span><span style="color: #000000;">&nbsp;'object')&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">typeof</span><span style="color: #000000;">&nbsp;obj;<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(obj&nbsp;</span><span style="color: #000000;">===</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">)&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;'</span><span style="color: #0000ff;">null</span><span style="color: #000000;">';<br><br>&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;i&nbsp;</span><span style="color: #0000ff;">in</span><span style="color: #000000;">&nbsp;_object_types)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(obj.constructor</span><span style="color: #000000;">===</span><span style="color: #000000;">_object_types[i])&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;i;<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;'unknow';<br>}<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;测试数据和相关代码</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;MyObject()&nbsp;{<br>}<br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;MyObject2()&nbsp;{<br>}<br>MyObject2.prototype&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;MyObject();<br><br>window.execScript(''</span><span style="color: #000000;">+</span><span style="color: #000000;"><br>'Function&nbsp;CreateVBArray()'&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;"><br>'&nbsp;&nbsp;Dim&nbsp;a(</span><span style="color: #000000;">2</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;">)'&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;"><br>'&nbsp;&nbsp;CreateVBArray&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;a'&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;"><br>'End&nbsp;Function',&nbsp;'VBScript');<br><br>document.writeln('</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">div&nbsp;id</span><span style="color: #000000;">=</span><span style="color: #000000;">dom&nbsp;style</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">display:none</span><span style="color: #000000;">"</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">dom</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">',&nbsp;'</span><span style="color: #000000;">/</span><span style="color: #000000;">div</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">');<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;测试代码</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;ax&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;ActiveXObject(</span><span style="color: #000000;">"</span><span style="color: #000000;">Microsoft.XMLHTTP</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;dom&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;document.getElementById('dom');<br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;vba&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;VBArray(CreateVBArray());<br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;obj&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;MyObject();<br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;obj2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;MyObject2();<br><br>document.writeln(objectTypes(vba),&nbsp;'</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">br</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">');<br>document.writeln(objectTypes(ax),&nbsp;'</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">br</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">');<br>document.writeln(objectTypes(obj),&nbsp;'</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">br</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">');<br>document.writeln(objectTypes(obj2),&nbsp;'</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">br</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">');<br>document.writeln(objectTypes(dom),&nbsp;'</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">br</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">');<br><br>在这个例子中，我们发现constructor属性被实现得并不完整。对于DOM对象、ActiveX对象<br>来说这个属性都没有正确的返回。<br><br>确切的说，DOM（包括Image)对象与ActiveX对象都不是标准JavaScript的对象体系中的，<br>因此它们也可能会具有自己的constructor属性，并有着与JavaScript不同的解释。因此，<br>JavaScript中不维护它们的constructor属性，是具有一定的合理性的。<br><br>另外的一些单体对象(而非构造器)，也不具有constructor属性，例如&#8220;Math&#8221;和&#8220;Debug&#8221;、<br>&#8220;Global&#8221;和&#8220;RegExp对象&#8221;。他们是JavaScript内部构造的，不应该公开构造的细节。<br><br>我们也发现实例obj的constructor指向function&nbsp;MyObject()。这说明JavaScript维护了对<br>象的constructor属性。——这与一些人想象的不一样。<br><br>然而再接下来，我们发现MyObject2()的实例obj2的constructor仍然指向function&nbsp;MyObject()。<br>尽管这很说不通，然而现实的确如此。——这到底是为什么呢？<br><br>事实上，仅下面的代码：<br></span><span style="color: #000000;">--------</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;MyObject2()&nbsp;{<br>}<br><br>obj2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;MyObject2();<br>document.writeln(MyObject2.prototype.constructor&nbsp;</span><span style="color: #000000;">===</span><span style="color: #000000;">&nbsp;MyObject2);<br></span><span style="color: #000000;">--------</span><span style="color: #000000;"><br>构造的obj2.constructor将正确的指向function&nbsp;MyObject2()。事实上，我们也会注意到这<br>种情况下，MyObject2的原型属性的constructor也正确的指向该函数。然而，由于JavaScript<br>要求指定prototype对象来构造原型链：<br></span><span style="color: #000000;">--------</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;MyObject2()&nbsp;{<br>}<br>MyObject2.prototype&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;MyObject();<br><br>obj2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;MyObject2();<br></span><span style="color: #000000;">--------</span><span style="color: #000000;"><br>这时，再访问obj2，将会得到新的原型(也就是MyObject2.prototype)的constructor属性。<br>因此，一切很明了：原型的属性影响到构造过程对对象的constructor的初始设定。<br><br>作为一种补充的解决问题的手段，JavaScript开发规范中说&#8220;need&nbsp;to&nbsp;remember&nbsp;to&nbsp;reset<br>the&nbsp;constructor&nbsp;property'，要求用户自行设定该属性。<br><br>所以你会看到更规范的JavaScript代码要求这样书写：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;维护constructor属性的规范代码</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;MyObject2()&nbsp;{<br>}<br>MyObject2.prototype&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;MyObject();<br>MyObject2.prototype.constructor&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;MyObject2;<br><br>obj2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;MyObject2();<br><br>更外一种解决问题的方法，是在function&nbsp;MyObject()中去重置该值。当然，这样会使<br>得执行效率稍低一点点：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;维护constructor属性的第二种方式</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;MyObject2()&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.constructor&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;arguments.callee;<br>&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;or,&nbsp;this.constructor&nbsp;=&nbsp;MyObject2;</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br>&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;<img src="http://www.phpweblog.net/Images/dot.gif"></span><span style="color: #008000;"><br></span><span style="color: #000000;">}<br>MyObject2.prototype&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;MyObject();<br><br>obj2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;MyObject2();<br><br></span><span style="color: #000000;">5</span><span style="color: #000000;">).&nbsp;析构问题<br></span><span style="color: #000000;">------</span><span style="color: #000000;"><br>JavaScript中没有析构函数，但却有&#8220;对象析构&#8221;的问题。也就是说，尽管我们不<br>知道一个对象什么时候会被析构，也不能截获它的析构过程并处理一些事务。然而，<br>在一些不多见的时候，我们会遇到&#8220;要求一个对象立即析构&#8221;的问题。<br><br>问题大多数的时候出现在对ActiveX&nbsp;Object的处理上。因为我们可能在JavaScript<br>里创建了一个ActiveX&nbsp;Object，在做完一些处理之后，我们又需要再创建一个。而<br>如果原来的对象供应者(Server)不允许创建多个实例，那么我们就需要在JavaScript<br>中确保先前的实例是已经被释放过了。接下来，即使Server允许创建多个实例，而<br>在多个实例间允许共享数据(例如OS的授权，或者资源、文件的锁)，那么我们在新<br>实例中的操作就可能会出问题。<br><br>可能还是有人不明白我们在说什么，那么我就举一个例子：如果创建一个Excel对象，<br>打开文件Ａ，然后我们save它，然后关闭这个实例。然后我们再创建Excel对象并打开<br>同一文件。——注意这时JavaScript可能还没有来得及析构前一个对象。——这时我们<br>再想Save这个文件，就发现失败了。下面的代码示例这种情况：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;JavaScript中的析构问题(ActiveX&nbsp;Object示例)</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #000000;">&lt;</span><span style="color: #000000;">script</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;strSaveLocation&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;'file:</span><span style="color: #008000;">//</span><span style="color: #008000;">/E:/1.xls'</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;createXLS()&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;excel&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;ActiveXObject(</span><span style="color: #000000;">"</span><span style="color: #000000;">Excel.Application</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;wk&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;excel.Workbooks.Add();<br>&nbsp;&nbsp;wk.SaveAs(strSaveLocation);<br>&nbsp;&nbsp;wk.Saved&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">true</span><span style="color: #000000;">;<br><br>&nbsp;&nbsp;excel.Quit();<br>}<br><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;writeXLS()&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;excel&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;ActiveXObject(</span><span style="color: #000000;">"</span><span style="color: #000000;">Excel.Application</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;wk&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;excel.Workbooks.Open(strSaveLocation);<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;sheet&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;wk.Worksheets(</span><span style="color: #000000;">1</span><span style="color: #000000;">);<br>&nbsp;&nbsp;sheet.Cells(</span><span style="color: #000000;">1</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">).Value&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;'测试字符串';<br>&nbsp;&nbsp;wk.SaveAs(strSaveLocation);<br>&nbsp;&nbsp;wk.Saved&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">true</span><span style="color: #000000;">;<br><br>&nbsp;&nbsp;excel.Quit();<br>}<br></span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">script</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br></span><span style="color: #000000;">&lt;</span><span style="color: #000000;">body</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">button&nbsp;onclick</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">createXLS()</span><span style="color: #000000;">"</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">创建</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">button</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">button&nbsp;onclick</span><span style="color: #000000;">=</span><span style="color: #000000;">"</span><span style="color: #000000;">writeXLS()</span><span style="color: #000000;">"</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">重写</span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">button</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br></span><span style="color: #000000;">&lt;/</span><span style="color: #000000;">body</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br><br>在这个例子中，在本地文件操作时并不会出现异常。——最多只是有一些内存垃<br>圾而已。然而，如果strSaveLocation是一个远程的URL，这时本地将会保存一个<br>文件存取权限的凭证，而且同时只能一个(远程的)实例来开启该excel文档并存<br>储。于是如果反复点击</span><span style="color: #000000;">"</span><span style="color: #000000;">重写</span><span style="color: #000000;">"</span><span style="color: #000000;">按钮，就会出现异常。<br><br>——注意，这是在SPS中操作共享文件时的一个实例的简化代码。因此，它并非<br>&#8220;学术的&#8221;无聊讨论，而且工程中的实际问题。<br><br>解决这个问题的方法很复杂。它涉及到两个问题：<br>&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;本地凭证的释放<br>&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;ActiveX&nbsp;Object实例的释放<br><br>下面我们先从JavaScript中对象的&#8220;失效&#8221;问题说起。简单的说：<br>&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;一个对象在其生存的上下文环境之外，即会失效。<br>&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;一个全局的对象在没有被执用(引用)的情况下，即会失效。<br><br>例如：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;JavaScript对象何时失效</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;testObject()&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;_obj1&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Object();<br>}<br><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;testObject2()&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;_obj2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Object();<br>&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;_obj2;<br>}<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;示例1</span><span style="color: #008000;"><br></span><span style="color: #000000;">testObject();<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;示例2</span><span style="color: #008000;"><br></span><span style="color: #000000;">testObject2()<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;示例3</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;obj3&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;testObject2();<br>obj3&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">;<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;示例4</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;obj4&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;testObject2();<br></span><span style="color: #0000ff;">var</span><span style="color: #000000;">&nbsp;arr&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;[obj4];<br>obj3&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">;<br>arr&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;[];<br><br>在这四个示例中：<br>&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;&#8220;示例1&#8221;在函数testObject()中构造了_obj1，但是在函数退出时，<br>&nbsp;&nbsp;&nbsp;&nbsp;它就已经离开了函数的上下文环境，因此_obj1失效了；<br>&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;&#8220;示例2&#8221;中，testObject2()中也构造了一个对象_obj2并传出，因<br>&nbsp;&nbsp;&nbsp;&nbsp;此对象有了&#8220;函数外&#8221;的上下文环境(和生存周期)，然而由于函数<br>&nbsp;&nbsp;&nbsp;&nbsp;的返回值没有被其它变量&#8220;持有&#8221;，因此_obj2也立即失效了；<br>&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;&#8220;示例3&#8221;中，testObject2()构造的_obj2被外部的变量obj3持用了，<br>&nbsp;&nbsp;&nbsp;&nbsp;这时，直到&#8220;obj3</span><span style="color: #000000;">=</span><span style="color: #0000ff;">null</span><span style="color: #000000;">&#8221;这行代码生效时，_obj2才会因为引用关系<br>&nbsp;&nbsp;&nbsp;&nbsp;消失而失效。<br>&nbsp;&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">&nbsp;与示例3相同的原因，&#8220;示例4&#8221;中的_obj2会在&#8220;arr</span><span style="color: #000000;">=</span><span style="color: #000000;">[]&#8221;这行代码<br>&nbsp;&nbsp;&nbsp;&nbsp;之后才会失效。<br><br>但是，对象的&#8220;失效&#8221;并不等会&#8220;释放&#8221;。在JavaScript运行环境的内部，没<br>有任何方式来确切地告诉用户&#8220;对象什么时候会释放&#8221;。这依赖于JavaScript<br>的内存回收机制。——这种策略与.NET中的回收机制是类同的。<br><br>在前面的Excel操作示例代码中，对象的所有者，也就是</span><span style="color: #000000;">"</span><span style="color: #000000;">EXCEL.EXE</span><span style="color: #000000;">"</span><span style="color: #000000;">这个进程<br>只能在&#8220;ActiveX&nbsp;Object实例的释放&#8221;之后才会发生。而文件的锁，以及操作<br>系统的权限凭证是与进程相关的。因此如果对象仅是&#8220;失效&#8221;而不是&#8220;释放&#8221;，<br>那么其它进程处理文件和引用操作系统的权限凭据时就会出问题。<br><br>——有些人说这是JavaScript或者COM机制的BUG。其实不是，这是ＯＳ、ＩＥ<br>和JavaScript之间的一种复杂关系所导致的，而非独立的问题。<br><br>Microsoft公开了解决这种问题的策略：主动调用内存回收过程。<br><br>在(微软的)JScript中提供了一个CollectGarbage()过程(通常简称GC过程)，<br>GC过程用于清理当前IE中的&#8220;失效的对象失例&#8221;，也就是调用对象的析构过程。<br><br>在上例中调用GC过程的代码是：<br></span><span style="color: #008000;">//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">&nbsp;处理ActiveX&nbsp;Object时，GC过程的标准调用方式</span><span style="color: #008000;"><br>//</span><span style="color: #008000;">---------------------------------------------------------</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">function</span><span style="color: #000000;">&nbsp;writeXLS()&nbsp;{<br>&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">(略<img src="http://www.phpweblog.net/Images/dot.gif">)</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br>&nbsp;&nbsp;excel.Quit();<br>&nbsp;&nbsp;excel&nbsp;</span><span style="color: #000000;">=</span><span st