<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>StephenChan&#039;s Tech Space &#187; JavaScript</title>
	<atom:link href="http://blog.endlesscode.com/category/javascript/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.endlesscode.com</link>
	<description>Stay Hungry. Stay Foolish.</description>
	<lastBuildDate>Tue, 25 Oct 2011 01:15:07 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>zz Dojo Javascript 编程规范</title>
		<link>http://blog.endlesscode.com/2010/06/25/zz-coding-convention-of-javascript/</link>
		<comments>http://blog.endlesscode.com/2010/06/25/zz-coding-convention-of-javascript/#comments</comments>
		<pubDate>Fri, 25 Jun 2010 05:46:58 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://blog.endlesscode.com/?p=977</guid>
		<description><![CDATA[虽然这说是Dojo的编程规范，但实际上大部分都是普遍应用的规范，所以就当是JavaScript的编程规范转载过来了 前言 相当不错的 Javascript 编程风格规范，建议大家采用此规范编写 Javascript。原文链接： http://dojotoolkit.org/developer/StyleGuide 。 翻译（Translated by）：i.feelinglucky{at}gmail.com from http://www.gracecode.com ，转载请注明出处、作者和翻译者，谢谢配合。 本文地址： http://code.google.com/p/grace/wiki/DojoStyle 。 序 Any violation to this guide is allowed if it enhances readability. 所有的代码都要变成可供他人容易阅读的。 快读参考 核心 API 请使用下面的风格： 结构 规则 注释 模块 小写 不要使用多重语义（Never multiple words） 类 骆驼 &#8230; <a href="http://blog.endlesscode.com/2010/06/25/zz-coding-convention-of-javascript/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<div style="width:80%;border:1px dotted #000000;padding:5px;text-align:center;margin:5px auto;">虽然这说是Dojo的编程规范，但实际上大部分都是普遍应用的规范，所以就当是JavaScript的编程规范转载过来了</div>
<h2>前言</h2>
<p style="max-width: 65em;">相当不错的 Javascript 编程风格规范，建议大家采用此规范编写 Javascript。原文链接： <a rel="nofollow" href="http://dojotoolkit.org/developer/StyleGuide">http://dojotoolkit.org/developer/StyleGuide</a> 。</p>
<p style="max-width: 65em;">翻译（Translated by）：i.feelinglucky{at}gmail.com from <a style="color: #0000cc;" rel="nofollow" href="http://www.gracecode.com">http://www.gracecode.com</a> ，转载请注明出处、作者和翻译者，谢谢配合。</p>
<p style="max-width: 65em;">本文地址： <a rel="nofollow" href="http://code.google.com/p/grace/wiki/DojoStyle">http://code.google.com/p/grace/wiki/DojoStyle</a> 。</p>
<h2>序</h2>
<p style="max-width: 65em;">Any violation to this guide is allowed if it enhances readability.</p>
<p style="max-width: 65em;">所有的代码都要变成可供他人容易阅读的。</p>
<h2>快读参考</h2>
<p style="max-width: 65em;">核心 API 请使用下面的风格：</p>
<table style="border-collapse: separate;" border="0">
<tbody>
<tr>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;"><strong>结构</strong></td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;"><strong>规则</strong></td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;"><strong>注释</strong></td>
</tr>
<tr>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">模块</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">小写</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">不要使用多重语义（Never multiple words）</td>
</tr>
<tr>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">类</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">骆驼</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;"></td>
</tr>
<tr>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">公有方法</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">混合</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">其他的外部调用也可以使用 lower_case()，这样的风格</td>
</tr>
<tr>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">公有变量</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">混合</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;"></td>
</tr>
<tr>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">常量</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">骆驼 或 大写</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;"></td>
</tr>
</tbody>
</table>
<p style="max-width: 65em;">下面的虽然不是必要的，但建议使用：</p>
<table style="border-collapse: separate;" border="0">
<tbody>
<tr>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;"><strong>结构</strong></td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;"><strong>规则</strong></td>
</tr>
<tr>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">私有方法</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">混合，例子：<tt style="font-size: 13px;">_mixedCase</tt></td>
</tr>
<tr>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">私有变量</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">混合，例子：<tt style="font-size: 13px;">_mixedCase</tt></td>
</tr>
<tr>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">方法（method）参数</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">混合，例子：<tt style="font-size: 13px;">_mixedCase, mixedCase</tt></td>
</tr>
<tr>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">本地（local）变量</td>
<td style="font-size: 13px; padding: 5px; border: 1px solid #aaaaaa;">混合，例子：<tt style="font-size: 13px;">_mixedCase, mixedCase</tt></td>
</tr>
</tbody>
</table>
<p><span id="more-977"></span></p>
<h2>命名规范</h2>
<ol style="max-width: 65em; padding-left: 40px;">
<li>变量名称 <em>必须为</em> 小写字母。</li>
<li>类的命名使用骆驼命名规则，例如：
<pre class="brush:javascript">Account, EventHandler</pre>
</li>
<li>常量 <em>必须</em> 在对象（类）或者枚举变量的前部声明。枚举变量的命名必须要有实际的意义，并且其成员 <em>必须</em> 使用骆驼命名规则或使用大写：</li>
<pre class="brush:javascript">var NodeTypes = {
    Element : 1,
    DOCUMENT: 2
}</pre>
<li>简写单词 <em>不能使用</em> 大写名称作为变量名：</li>
<pre class="brush:javascript">getInnerHtml(), getXml(), XmlDocument</pre>
<li>方法的命令 <em>必须</em> 为动词或者是动词短语：</li>
<pre class="brush:javascript">obj.getSomeValue()</pre>
<li>公有类的命名 <em>必须</em> 使用混合名称（mixedCase）命名。</li>
<li>CSS 变量的命名 <em>必须</em> 使用其对应的相同的公共类变量。</li>
<li>私有类的变量属性成员 <em>必须</em> 使用混合名称（mixedCase）命名，并前面下下划线（<tt style="font-size: 13px;">_</tt>）。例如：</li>
<pre class="brush:javascript">var MyClass = function(){
   var _buffer;
   this.doSomething = function(){
   };
}</pre>
<li>变量如果设置为私有，则前面 <em>必须</em> 添加下划线。</li>
<pre class="brush:javascript">this._somePrivateVariable = statement;</pre>
<li>通用的变量 <em>必须</em> 使用与其名字一致的类型名称：</li>
<pre class="brush:javascript">setTopic(topic) // 变量 topic 为 Topic 类型的变量</pre>
<li>所有的变量名 <em>必须</em> 使用英文名称。</li>
<li>变量如有较广的作用域（large scope），必须使用全局变量；此时可以设计成一个类的成员。相对的如作用域较小或为私有变量则使用简洁的单词命名。</li>
<li>如果变量有其隐含的返回值，则避免使用其相似的方法：</li>
<pre class="brush:javascript">getHandler(); // 避免使用 getEventHandler()</pre>
<li>公有变量必须清楚的表达其自身的属性，避免字义含糊不清，例如：</li>
<pre class="brush:javascript">MouseEventHandler，而非 MseEvtHdlr。</pre>
<p>请再次注意这条规定，这样做得的好处是非常明显的。它能明确的表达表达式所定义的含义。例如：</p>
<pre class="brush:javascript">dojo.events.mouse.Handler // 而非 dojo.events.mouse.MouseEventHandler</pre>
<li>类/构造函数 <em>可以使用</em> 扩展其基类的名称命名，这样可以正确、迅速的找到其基类的名称：</li>
<pre class="brush:javascript">EventHandler
UIEventHandler
MouseEventHandler</pre>
<p>基类可以在明确描述其属性的前提下，缩减其命名：</p>
<pre class="brush:javascript">MouseEventHandler as opposed to MouseUIEventHandler.</pre>
</ol>
<h2>特殊命名规范</h2>
<ol style="max-width: 65em; padding-left: 40px;">
<li>术语 &#8220;get/set&#8221; 不要和一个字段相连，除非它被定义为私有变量。</li>
<li>前面加 &#8220;is&#8221; 的变量名 <em>应该</em> 为布尔值，同理可以为 &#8220;has&#8221;, &#8220;can&#8221; 或者 &#8220;should&#8221;。</li>
<li>术语 &#8220;compute&#8221; 作为变量名应为已经计算完成的变量。</li>
<li>术语 &#8220;find&#8221; 作为变量名应为已经查找完成的变量。</li>
<li>术语 &#8220;initialize&#8221; 或者 &#8220;init&#8221; 作为变量名应为已经实例化（初始化）完成的类或者其他类型的变量。</li>
<li>UI （用户界面）控制变量应在名称后加控制类型，例如： leftComboBox, TopScrollPane。</li>
<li>复数必须有其公共的名称约定（原文：Plural form MUST be used to name collections）。</li>
<li>带有 &#8220;num&#8221; 或者 &#8220;count&#8221; 开头的变量名约定为数字（对象）。</li>
<li>重复变量建议使用 &#8220;i&#8221;, &#8220;j&#8221;, &#8220;k&#8221; （依次类推）等名称的变量。</li>
<li>补充用语必须使用补充词，例如： get/set, add/remove, create/destroy, start/stop, insert/delete, begin/end, etc.</li>
<li>能缩写的名称尽量使用缩写。</li>
<li>避免产生歧义的布尔变量名称，例如：</li>
<pre class="brush:javascript">isNotError, isNotFound 为非法</pre>
<li>错误类建议在变量名称后加上 &#8220;Exception&#8221; 或者 &#8220;Error&#8221;。</li>
<li>方法如果返回一个类，则应该在名称上说明返回什么；如果是一个过程，则应该说明做了什么。</li>
</ol>
<h2>文件</h2>
<ol style="max-width: 65em; padding-left: 40px;">
<li>缩进请使用 4 个空白符的制表位。</li>
<li>如果您的编辑器支持 文件标签_（file tags），请加添如下的一行使我们的代码更容易阅读：
<pre class="brush:javascript">// vim:ts=4:noet:tw=0:
//译注：老外用 VIM 编辑器比较多，此条可以选择遵循。</pre>
</li>
<li>代码折叠必须看起来是完成并且是合乎逻辑的：
<pre class="brush:javascript">var someExpression = Expression1
    + Expression2
    + Expression3;

var o = someObject.get(
    Expression1,
    Expression2,
    Expression3
);

//注：表达式的缩进与变量声明应为一致的。
//注：函数的参数应采用明确的缩进，缩进规则与其他块保持一致。</pre>
</li>
</ol>
<h2>变量</h2>
<ol style="max-width: 65em; padding-left: 40px;">
<li>变量必须在声明初始化以后才能使用，即便是 NULL 类型。</li>
<li>变量不能产生歧义。</li>
<li>相关的变量集应该放在同一代码块中，非相关的变量集不应该放在同一代码块中。</li>
<li>变量应该尽量保持最小的生存周期。</li>
<li>循环/重复变量的规范：
<ul>
<li>只有循环控制块的话，则必须使用 FOR 循环。</li>
</ul>
<ul>
<li>循环变量应该在循环开始前就被初始化；如使用 FOR 循环，则使用 FOR 语句初始化循环变量。</li>
</ul>
<ul>
<li>&#8220;do &#8230; while&#8221; 语句是被允许的。</li>
</ul>
<ul>
<li>&#8220;break&#8221; 和 &#8220;continue&#8221; 语句仍然允许使用（但请注意）。</li>
</ul>
</li>
<li>条件表达式
<ul>
<li>应该尽量避免复杂的条件表达式，如有必要可以使用临时布尔变量。</li>
</ul>
<ul>
<li>The nominal case SHOULD be put in the &#8220;if&#8221; part and the exception in the &#8220;else&#8221; part of an &#8220;if&#8221; statement.</li>
</ul>
<ul>
<li>应避免在条件表达式中加入块。</li>
</ul>
</li>
<li>杂项
<ul>
<li>尽量避免幻数（Magic numbers），他们应该使用常量来代替。</li>
</ul>
<ul>
<li>浮点变量必须指明小数点后一位（即使是 0）。</li>
</ul>
<ul>
<li>浮点变量必须指明实部，即使它们为零（使用 0. 开头）。</li>
</ul>
</li>
</ol>
<h2>布局</h2>
<h3>块</h3>
<ol style="max-width: 65em; padding-left: 40px;">
<li>普通代码段 <em>应该</em> 看起来如下：</li>
<pre class="brush:javascript">while (!isDone){
    doSomething();
    isDone = moreToDo();
}</pre>
<li>IF 语句 <em>应该</em> 看起来像这样：</li>
<pre class="brush:javascript">if (someCondition){
    statements;
} else if (someOtherCondition){
    statements;
} else {
    statements;
}</pre>
<li>FOR 语句 <em>应该</em> 看起来像这样：</li>
<pre class="brush:javascript">for (initialization; condition; update){
    statements;
}</pre>
<li>WHILE 语句 <em>应该</em> 看起来像这样：</li>
<pre class="brush:javascript">while (!isDone) {
    doSomething();
    isDone = moreToDo();
}</pre>
<li>DO &#8230; WHILE 语句 <em>应该</em> 看起来像这样：</li>
<pre class="brush:javascript">do {
    statements;
} while (condition);</pre>
<li>SWITCH 语句 <em>应该</em> 看起来像这样：</li>
<pre class="brush:javascript">switch (condition) {
case ABC:
    statements;
    //  fallthrough
case DEF:
    statements;
    break;
default:
    statements;
    break;
}</pre>
<li>TRY &#8230; CATCH 语句 <em>应该</em> 看起来像这样：</li>
<pre class="brush:javascript">try {
    statements;
} catch(ex) {
    statements;
} finally {
    statements;
}</pre>
<li>单行的 IF &#8211; ELSE，WHILE 或者 FOR 语句也 <em>必须</em> 加入括号，不过他们可以这样写：</li>
<pre class="brush:javascript">if (condition){ statement; }
while (condition){ statement; }
for (intialization; condition; update){ statement; }</pre>
</ol>
<h3>空白</h3>
<ol style="max-width: 65em; padding-left: 40px;">
<li>操作符 <em>建议</em> 使用空格隔开（包括三元操作符）。</li>
<li>下面的关键字 <em>避免使用</em> 空白隔开：
<ul style="max-width: 65em; padding-left: 40px;">
<li>break</li>
<li>catch</li>
<li>continue</li>
<li>do</li>
<li>else</li>
<li>finally</li>
<li>for</li>
<li>function （如果为匿名函数，例如：var foo = function(){}; ）</li>
<li>if</li>
<li>return</li>
<li>switch</li>
<li>this</li>
<li>try</li>
<li>void</li>
<li>while</li>
<li>with</li>
</ul>
</li>
<li>下面的关键字必须使用空白隔开：
<ul style="max-width: 65em; padding-left: 40px;">
<li>case</li>
<li>default</li>
<li>delete</li>
<li>function （如果为申明，例如：function foo(){}; ）</li>
<li>in</li>
<li>instanceof</li>
<li>new</li>
<li>throw</li>
<li>typeof</li>
<li>var</li>
</ul>
</li>
<li><strong>逗号（,）</strong> <em>建议</em> 使用空白隔开。</li>
<li><strong>冒号（:）</strong> <em>建议</em> 使用空白隔开。</li>
<li><strong>点（.）</strong> 在后部 <em>建议</em> 使用空白隔开。</li>
<li><strong>点（.）</strong> <em>避免</em> 在前部使用空白。</li>
<li><strong>函数调用和方法</strong> <em>避免</em> 使用空白，例如：<tt style="font-size: 13px;"> doSomething(someParameter); // 而非 doSomething (someParameter)</tt></li>
<li><strong>逻辑块</strong> 之间使用空行。</li>
<li><strong>声明</strong> <em>建议</em> 对齐使其更容易阅读。</li>
</ol>
<h3>注释</h3>
<ol style="max-width: 65em; padding-left: 40px;">
<li>生涩的代码就 <em>没有必要</em> 添加注释了，首先您需要 <strong>重写</strong> 它们。</li>
<li>所有的注释请使用英文。</li>
<li>从已解决的方案到未开发的功能，注释 <em>必须</em> 与代码相关。</li>
<li>大量的变量申明后 <em>必须</em> 跟随一段注释。</li>
<li>注释需要说明的是代码段的用处，尤其是接下来的代码段。</li>
<li>注释 <em>没有必要</em> 每行都添加。</li>
</ol>
<h2>文档</h2>
<p style="max-width: 65em;">下面提供了一些基本的函数或者对象的描述方法：</p>
<ul style="max-width: 65em; padding-left: 40px;">
<li><strong>总结（summary）</strong>: 简短的表述此函数或者对象实现的目的</li>
<li><strong>描述（description）</strong>: 对于此函数或者类的简短的描述</li>
<li><strong>返回（return）</strong>: 描述此函数返回什么（并不包括返回类型）</li>
</ul>
<h3>基本函数信息</h3>
<pre class="brush:javascript">function(){
    // summary: Soon we will have enough treasure to rule all of New Jersey.
    // description: Or we could just get a new roomate.
    //          Look, you go find him.  He don't yell at you.
    //          All I ever try to do is make him smile and sing around
    //          him and dance around him and he just lays into me.
    //          He told me to get in the freezer 'cause there was a carnival in there.
    // returns:  Look, a Bananarama tape!
}</pre>
<h3>对象函数信息</h3>
<p style="max-width: 65em;">没有返回值描述</p>
<pre class="brush:javascript">{
    // summary: Dingle, engage the rainbow machine!
    // description:
    //          Tell you what, I wish I was--oh my g--that beam,
    //          coming up like that, the speed, you might wanna adjust that.
    //          It really did a number on my back, there. I mean, and I don't
    //          wanna say whiplash, just yet, cause that's a little too far,
    //          but, you're insured, right?
}</pre>
<h3>函数的声明</h3>
<p style="max-width: 65em;">在有的情况下，对于函数的调用和声明是隐义（invisible）的。在这种情况下，我们没有办法在函数中加入说明等（供程序调用）。如果您遭遇了这种情况，您可以使用一个类来封装函数。</p>
<p style="max-width: 65em;">注：此此方法只能在函数没有初始化的参数情况下。如过不是，则它们会被忽略。</p>
<pre class="brush:javascript">dojo.declare(
    "foo",
    null,
    {
        // summary: Phew, this sure is relaxing, Frylock.
        // description:
        //              Thousands of years ago, before the dawn of
        //              man as we knew him, there was Sir Santa of Claus: an
        //              ape-like creature making crude and pointless toys out
        //              of dino-bones, hurling them at chimp-like creatures with
        //              crinkled hands regardless of how they behaved the
        //              previous year.
        // returns: Unless Carl pays tribute to the Elfin Elders in space.
    }
);</pre>
<h3>参数</h3>
<ol style="max-width: 65em; padding-left: 40px;">
<li>简单类型</li>
<p>简单的类型的参数可以直接在函数参数定义中注释说明。</p>
<pre class="brush:javascript">function(/*String*/ foo, /*int*/ bar)...</pre>
<li>可变类型参数<br />
下面是几个修饰符供参考：</p>
<ul style="max-width: 65em; padding-left: 40px;">
<li><strong>?</strong> 可选参数</li>
<li><strong>&#8230;</strong> 说面参数范围不确定</li>
<li><strong><a></a></strong> 数组</li>
</ul>
<pre class="brush:javascript">function(/*String?*/ foo, /*int...*/ bar, /*String[]*/ baz)...</pre>
</li>
<li>全局参数描述</li>
<p>如果你想增加一个描述，你可以将它们移至初始化块。<br />
基本信息格式为： *关键字* 描述字段（*key* Descriptive sentence）<br />
参数和变量的格式为： *关键字* ~*类型*~ 描述字段（ *key* ~*type*~ Descriptive sentence）<br />
注： *关键字* 和 ~*类型*~ 可以使用任何字母和数字表述。</p>
<pre class="brush:javascript">function (foo, bar) {
    // foo: String
    //      used for being the first parameter
    // bar: int
    //      used for being the second parameter
}</pre>
</ol>
<h3>变量</h3>
<p style="max-width: 65em;">由于实例变量、原型变量和外部变量的声明是一致的，所以有很多的方法声明、修改变量。具体的如何定义和定位应在变量最先出现的位置指明变量的名称、类型、作用域等信息。</p>
<pre class="brush:javascript">function foo() {
    // myString: String
    // times: int
    //        How many times to print myString
    // separator: String
    //        What to print out in between myString*
    this.myString = "placeholder text";
    this.times = 5;
}

foo.prototype.setString = function (myString) {
    this.myString = myString;
}

foo.prototype.toString = function() {
    for(int i = 0; i &lt; this.times; i++) {
        dojo.debug(this.myString);
        dojo.debug(foo.separator);
        }
}
foo.separator = "=====";</pre>
<h4>对象中的变量注释</h4>
<p style="max-width: 65em;">应使用和对象值和方法一致的标注方式，比如在他们声明的时候：</p>
<pre class="brush:javascript">{
    // key: String
    //      A simple value
    key: "value",
    // key2: String
    //      Another simple value
}</pre>
<h3>返回值</h3>
<p style="max-width: 65em;">因为函数可以同时返回多个不同（类型）的值，所以应每个返回值之后加入返回类型的注释。注释在行内注释即可，如果所有的返回值为同一类型，则指明返回的类型；如为多个不同的返回值，则标注返回类型为&#8221;mixed&#8221;。</p>
<pre class="brush:javascript">function() {
    if (arguments.length) {
        return "You passed argument(s)"; // String
    } else {
        return false; // Boolean
    }
}</pre>
<h3>伪代码（有待讨论）</h3>
<p style="max-width: 65em;">有时候您需要在函数或者类中添加对于此函数和类的功能性流程描述。如果您打算这样做，您可以使用 <tt style="font-size: 13px;">/*======== </tt>（= 字符最好出现 5 次或者更多），这样做的好处就是可以不用将这些东西加入代码（译注：原作者的意思可能为代码管理系统）。</p>
<p style="max-width: 65em;">这样看起来在 <tt style="font-size: 13px;">/*===== </tt>和 <tt style="font-size: 13px;">=====*/ </tt>会有非常长的一段注释，等待功能调整完毕以后就可以考虑是否删除。</p>
<pre class="brush:javascript">/*=====
module.pseudo.kwArgs = {
        // url: String
    //          The location of the file
    url: "",
    // mimeType: String
    //          text/html, text/xml, etc
    mimeType: ""
}
=====*/

function(/*module.pseudo.kwArgs*/ kwArgs){
    dojo.debug(kwArgs.url);
        dojo.debug(kwArgs.mimeType);
}</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.endlesscode.com/2010/06/25/zz-coding-convention-of-javascript/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JavaScript散记</title>
		<link>http://blog.endlesscode.com/2010/06/02/javascript-tips/</link>
		<comments>http://blog.endlesscode.com/2010/06/02/javascript-tips/#comments</comments>
		<pubDate>Wed, 02 Jun 2010 14:15:03 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://blog.endlesscode.com/?p=718</guid>
		<description><![CDATA[跨浏览器通信 建立跨浏览器通信有两个前提条件 两个窗口都包含来自同一个域的页面； 其中一个窗口包含对另一个窗口的引用。 第一个条件是JavaScript同源策略的结果，保护用户的隐私，第二个条件是为了使一个窗口知道另一个窗口的存在。实现通信主要是涉及到window对象的name和opener属性，以及open()方法。 window.name属性的作用是为HTML链接的target属性作引导的，同时它也可以引导弹出窗口。它的默认值为空，但可以设置的。 window.name = "endlesscode"; 点击带有此target的链接，比如&#60;a href=&#8221;somepage.html&#8221; target=&#8221;endlesscode&#8221;&#62;，该链接就会在window.name为&#8221;endlesscode&#8221;的窗口打开。另外，也可以在window.open()方法中使用name，例如： window.open("somepage.html", "endlesscode", [arguments]); 这样浏览器就会查找名字叫做&#8221;endlesscode&#8221;的窗口。如果它找到一个，somepage.html就会在这个窗口打开。如果没有找到，就找开一个新窗口，并将name命名为&#8221;endlesscode&#8221;。其实像wp的预览、优酷的视频观看页面以及卓越的书目录页面都是使用这种方式在同一个页面打开的。 window.opener属性是弹出窗口指回主窗口的引用，如果新页面被载入到弹出窗口中（如果用户点击了一个链接），opener属性仍旧可用。如果新页面是载入到主窗口中，则可以通过在弹出窗口中 opener.ST_newWindow = window; 来在主窗口中保存弹出窗口的引用。 弹出窗口拦截软件 主流的浏览器一般都会有弹出窗口拦截的功能，可以拦截页面上的弹出窗口，但实际上浏览器厂商并没有简单地禁用了window.open()方法，因为弹出窗口还是有合理的使用方法。相反，它们只拦截未被（用户）请求的弹出框。而对于“未被请求的弹出窗口”，浏览器厂商一般的定义似乎是：在用户点击之后打开的窗口是被请求的，而其他的则不是被请求的。因此，下面的代码是可以绕过弹出窗口过滤器的： var popup; document.onclick = function() { popup = window.open("somepage.html", "name", [arguments]); } 这样，用户点击文档的任何位置，弹出窗口都会跳出来，因为点击动作是用户请求的。 href与replace() location.href和location.replace()有同样的功能是，使浏览器载入新的页面，但并非完全一样。如果你改变了页面的location.href，就好像用户点击了某个链接，于是浏览器加载一个新页面。这个新页面就会成为窗口历史中的一项新条目。而如果使用replace()，新页面就会直接覆盖窗口历史当前页面的条目。 在IE中创建并添加option元素 在Explorer中createElement(option)是可以的，但是不直接支持appendChild(option)，想要在IE为select添加一个option的话，需要调用： &#8230; <a href="http://blog.endlesscode.com/2010/06/02/javascript-tips/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<h4>跨浏览器通信</h4>
<p>建立跨浏览器通信有两个前提条件</p>
<ol>
<li>两个窗口都包含来自同一个域的页面；</li>
<li>其中一个窗口包含对另一个窗口的引用。</li>
</ol>
<p>第一个条件是JavaScript同源策略的结果，保护用户的隐私，第二个条件是为了使一个窗口知道另一个窗口的存在。实现通信主要是涉及到window对象的name和opener属性，以及open()方法。</p>
<p>window.name属性的作用是为HTML链接的target属性作引导的，同时它也可以引导弹出窗口。它的默认值为空，但可以设置的。</p>
<pre class="brush:js">window.name = "endlesscode";</pre>
<p>点击带有此target的链接，比如&lt;a href=&#8221;somepage.html&#8221; target=&#8221;endlesscode&#8221;&gt;，该链接就会在window.name为&#8221;endlesscode&#8221;的窗口打开。另外，也可以在window.open()方法中使用name，例如：</p>
<pre class="brush:js">window.open("somepage.html", "endlesscode", [arguments]);</pre>
<p>这样浏览器就会查找名字叫做&#8221;endlesscode&#8221;的窗口。如果它找到一个，somepage.html就会在这个窗口打开。如果没有找到，就找开一个新窗口，并将name命名为&#8221;endlesscode&#8221;。其实像wp的预览、优酷的视频观看页面以及卓越的书目录页面都是使用这种方式在同一个页面打开的。<br />
window.opener属性是弹出窗口指回主窗口的引用，如果新页面被载入到弹出窗口中（如果用户点击了一个链接），opener属性仍旧可用。如果新页面是载入到主窗口中，则可以通过在弹出窗口中</p>
<pre class="brush:js">opener.ST_newWindow = window;</pre>
<p>来在主窗口中保存弹出窗口的引用。<span id="more-718"></span></p>
<h4>弹出窗口拦截软件</h4>
<p>主流的浏览器一般都会有弹出窗口拦截的功能，可以拦截页面上的弹出窗口，但实际上浏览器厂商并没有简单地禁用了window.open()方法，因为弹出窗口还是有合理的使用方法。相反，它们只拦截未被（用户）请求的弹出框。而对于“未被请求的弹出窗口”，浏览器厂商一般的定义似乎是：在用户点击之后打开的窗口是被请求的，而其他的则不是被请求的。因此，下面的代码是可以绕过弹出窗口过滤器的：</p>
<pre class="brush:js">var popup;
document.onclick = function() {
    popup = window.open("somepage.html", "name", [arguments]);
}</pre>
<p>这样，用户点击文档的任何位置，弹出窗口都会跳出来，因为点击动作是用户请求的。</p>
<h4>href与replace()</h4>
<p>location.href和location.replace()有同样的功能是，使浏览器载入新的页面，但并非完全一样。如果你改变了页面的location.href，就好像用户点击了某个链接，于是浏览器加载一个新页面。这个新页面就会成为窗口历史中的一项新条目。而如果使用replace()，新页面就会直接覆盖窗口历史当前页面的条目。</p>
<h4>在IE中创建并添加option元素</h4>
<p>在Explorer中createElement(option)是可以的，但是不直接支持appendChild(option)，想要在IE为select添加一个option的话，需要调用：</p>
<pre class="brush:js">/* 方法一 使用select.options.add */
var newOpt = document.createElement("option");
newOpt.text = "text";
newOpt.value = "value";
select.options.add(newOpt);

/* 方法二 使用createTextNode建立option标签内的文字内容 */
var newOpt = document.createElement("option");
var oText = document.createTextNode("text");
newOpt.appendChild(oText);
newOpt.setAttribute("value", "value");
select.appendChild(newOpt);</pre>
<h4>更改样式表</h4>
<p>成功进行样式表编辑的第一个必要条件就是支持document.styleSheets节点序列，document.styleSheets包含了link和style标签里面的样式表，以数组的形式组织，并按照在源代码中的出现顺序被一一编号。</p>
<p><img class="aligncenter size-full wp-image-729" title="stylesheet" src="http://blog.endlesscode.com/wp-content/uploads/2010/06/stylesheet.jpg" alt="stylesheet" width="276" height="138" /></p>
<p>访问样式表中的所有规则，Mozilla使用w3c规范定义的cssRules[]节点序列，而Explorer必须使用微软专有的rules[]节点序列，幸运的是，这两个属性除了名字不同外几乎是一样的。</p>
<pre class="brush:js">currentSheet = document.styleSheets[0];
if (currentSheet.cssRules)
    sheetRules = currentSheet.cssRules;
else if (currentSheet.rules)
    sheetRules = currentSheet.rules;
else return;</pre>
<p>每一条规则都有一个selectorText属性，以字符串的形式保存着规则的选择符：</p>
<pre class="brush:js">/* 接上面 */
for (var i=0;i&lt;sheetRules.length;i++)
    alert(sheetRules[i].selectorText);</pre>
<p>每条规则都有一个style属性，它用起来像单个HTML元素的style属性：</p>
<pre class="brush:js">/* 接上面 */
/* 第一条规则的color被设置为#cccccc */
var currentRule = sheetRules[0];
currentRule.style.color = "#cccccc";</pre>
<p>在读取样式表完整文本上还没有跨浏览器的方法，cssText属性可以访问css文本内容，但浏览器们没有在这个属性的作用域上完全达成一致：</p>
<pre class="brush:js">document.styleSheets[0].cssText;  //Windows &amp; Mac 支持
document.styleSheets[0].cssRules[0].cssText;  //Mac下的Explorer和Mozilla
document.styleSheets[0].cssRules[0].style.cssText;   //所有浏览器都支持</pre>
<p>添加和删除某个规则，w3c使用insertRule/deleteRule，而Explorer使用微软专用的addRule/removeRule。Safari和Opera完全不支持添加和删除的行为。</p>
<pre class="brush:js">/* w3c */
var x = document.styleSheets[0];
x.insertRule('PRE { font:0.9em verdana }', 2); // (ruleContent, ruleIndex)
x.deleteRule(2); //(ruleIndex)

/* IE */
var x = document.styleSheets[0];
x.addRule('PRE', 'font:0.9em verdana', 2); // (selector, declaration, index)
x.removeRule(2); //(index)</pre>
<h4>其它</h4>
<ul>
<li>readystatechange事件在Explorer中，是可以应用在所有的元素中，但其他浏览器只支持将它用在XMLHttpRequest对象上。</li>
<li>load事件是在页面完全加载后（包括图片等文件），才会触发的。而无论什么原因引起页面释放时，会触发unload事件，包括点击一个链接、提交表单、关闭浏览器窗口等等。</li>
<li>取消事件传播:</li>
</ul>
<pre class="brush:js">var evt = [the event object];
if (evt.stopPropagation)   // w3c
    evt.stopPropagation();
evt.cancelBubble = true;  // ie</pre>
<ul>
<li>appendChild、insertBefore、replaceChild三个dom的方法如果要插入的元素已经存在，则移除从当前的结构中移除要插入的元素，其他的元素维持不变。</li>
<li>childNodes[]包含所有的子节点，children[]包括类型为元素节点的子节点而不包含文本类型的子节点。但children不是w3c dom规范的一部分。</li>
<li>Explorer并非不允许设置input.type，而是动态创建的input在添加到文档中之前，只允许读/写一次，即:</li>
</ul>
<pre class="brush:js">/* 不可行 */
newField.type = "checkbox";

/* 可行 */
newField.setAttribute("type", "checkbox");</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.endlesscode.com/2010/06/02/javascript-tips/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JavaScript中的一些定位属性</title>
		<link>http://blog.endlesscode.com/2010/03/16/position-property-of-element-in-javascript/</link>
		<comments>http://blog.endlesscode.com/2010/03/16/position-property-of-element-in-javascript/#comments</comments>
		<pubDate>Wed, 17 Mar 2010 06:03:45 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://blog.endlesscode.com/?p=381</guid>
		<description><![CDATA[有这张图就够了，简单地说明一下 以Height为例，Width同理： div.clientHeight：可见窗口除去了margin+border之后的长度。 div.offsetHeight：在div.clientHeight的基础上加了border和滚动条的长度。 div.scrollHeight：就是元素内容的实际高度。 以Top为例，Left同理： div.clientTop：margin之后padding之前的长度值。 div.offsetTop：该元素的上border的上边缘 到 该元素的offsetParent的上border内边缘的垂直距离。 div.scrollTop：对象的最顶部到对象在当前窗口显示的范围内的顶边的距离，即是在出现了纵向滚动条的情况下，滚动条拉动的距离。 关于offsetParent，不同的浏览器有不同的实现算法，有一种常见布局在各种浏览器中 offsetParent 是一样的，那就是：外层元素 div 的 position 计算值是 relative、absolute 时，内层元素 div 的 offsetParent 总是外层元素 div。]]></description>
			<content:encoded><![CDATA[<p><img class="aligncenter size-full wp-image-382" title="js" src="http://blog.endlesscode.com/wp-content/uploads/2010/03/js.jpg" alt="js" width="550" height="543" /></p>
<p>有这张图就够了，简单地说明一下</p>
<p>以Height为例，Width同理：</p>
<ul>
<li>div.clientHeight：可见窗口除去了margin+border之后的长度。</li>
<li>div.offsetHeight：在div.clientHeight的基础上加了border和滚动条的长度。</li>
<li>div.scrollHeight：就是元素内容的实际高度。</li>
</ul>
<p><span id="more-381"></span>以Top为例，Left同理：</p>
<ul>
<li>div.clientTop：margin之后padding之前的长度值。</li>
<li>div.offsetTop：该元素的上border的上边缘  到  该元素的offsetParent的上border内边缘的垂直距离。</li>
<li>div.scrollTop：对象的最顶部到对象在当前窗口显示的范围内的顶边的距离，即是在出现了纵向滚动条的情况下，滚动条拉动的距离。</li>
</ul>
<p>关于offsetParent，不同的浏览器有不同的实现算法，有一种常见布局在各种浏览器中 offsetParent 是一样的，那就是：外层元素 div 的 position 计算值是 relative、absolute 时，内层元素 div 的 offsetParent 总是外层元素 div。</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.endlesscode.com/2010/03/16/position-property-of-element-in-javascript/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JavaScript中Function和Object的关系</title>
		<link>http://blog.endlesscode.com/2010/01/24/javascript-function-object/</link>
		<comments>http://blog.endlesscode.com/2010/01/24/javascript-function-object/#comments</comments>
		<pubDate>Sun, 24 Jan 2010 16:55:55 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://blog.endlesscode.com/?p=155</guid>
		<description><![CDATA[Function.__proto__指向Function.prototype，这导致： Function.constructor === Function Function instanceof Function == true 即Function是它自己的构造器。 Object.__proto__指向Function.prototype，即Object也是Function构造的实例，因此有： Object instanceof Function == true 同时也等价于： Object.constructor === Function 而Function.prototype.__proto__又是指向Object.prototype，即Function.prototype是Object构造的实例，因此有： Function instanceof Object == true Object instanceof Object == true Foo.__proto__指向了Function.prototype，可以看到自定义的函数Foo其实就是Function的一个实例： Foo instanceof Function == true 参考： JavaScript Object &#8230; <a href="http://blog.endlesscode.com/2010/01/24/javascript-function-object/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p style="text-align: center; "><img class="size-full wp-image-156 aligncenter" title="jsobj" src="http://blog.endlesscode.com/wp-content/uploads/2010/01/jsobj.jpg" alt="jsobj" width="611" height="760" /></p>
<ul>
<li>Function.__proto__指向Function.prototype，这导致：</li>
</ul>
<pre class="brush:javascript">Function.constructor === Function
Function instanceof Function == true</pre>
<p>即Function是它自己的构造器。</p>
<ul>
<li>Object.__proto__指向Function.prototype，即Object也是Function构造的实例，因此有：</li>
</ul>
<pre class="brush:javascript">Object instanceof Function == true</pre>
<p>同时也等价于：</p>
<pre class="brush:javascript">Object.constructor === Function</pre>
<p>而Function.prototype.__proto__又是指向Object.prototype，即Function.prototype是Object构造的实例，因此有：</p>
<pre class="brush:javascript">Function instanceof Object == true
Object instanceof Object == true</pre>
<ul>
<li>Foo.__proto__指向了Function.prototype，可以看到自定义的函数Foo其实就是Function的一个实例：</li>
</ul>
<pre class="brush:javascript">Foo instanceof Function == true</pre>
<p>参考：</p>
<ul>
<li><a href="http://www.mollypages.org/misc/js.mp" target="_blank">JavaScript Object Hierarchy</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.endlesscode.com/2010/01/24/javascript-function-object/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>浅析JavaScript的原型链</title>
		<link>http://blog.endlesscode.com/2010/01/23/javascript-prototype-chain/</link>
		<comments>http://blog.endlesscode.com/2010/01/23/javascript-prototype-chain/#comments</comments>
		<pubDate>Sat, 23 Jan 2010 19:40:47 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://blog.endlesscode.com/?p=136</guid>
		<description><![CDATA[原型的含义是指：如果构造器有个原型对象A，则由该构造器创建的实例(Object Instance)都必然复制于A。““在JavaScript中，对象实例(Object Instance)并没有原型，而构造器(Constructor)有原型，属性&#8217;&#60;构造器&#62;.prototype&#8217;指向原型。对象只有“构造自某个原型”的问题，并不存在“持有（或拥有）某个原型”的问题。””如何理解这一句话？ 代码1： function myFunc() { var name = "stephenchan"; var age = 23; function code() { alert("Hello World!"); }; } var obj = new myFunc(); //输出undefined，对象实例没有原型 alert(obj.prototype); //输出myFunc的函数代码，obj由myFunc构造出来的 alert(obj.constructor); //输出true alert(obj.constructor == myFunc); //输出[object Object]，说明myFunc的原型是一个对象 alert(myFunc.prototype); //输出function Function() &#8230; <a href="http://blog.endlesscode.com/2010/01/23/javascript-prototype-chain/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><strong>原型的含义</strong>是指：如果构造器有个原型对象A，则由该构造器创建的实例(Object Instance)都必然复制于A。““在JavaScript中，对象实例(Object Instance)并没有原型，而构造器(Constructor)有原型，属性&#8217;&lt;构造器&gt;.prototype&#8217;指向原型。对象只有“构造自某个原型”的问题，并不存在“持有（或拥有）某个原型”的问题。””如何理解这一句话？</p>
<p>代码1：</p>
<pre class="brush:javascript">function myFunc() {
	var name = "stephenchan";
	var age = 23;
	function code() {
		alert("Hello World!");
	};
}
var obj = new myFunc();
//输出undefined，对象实例没有原型
alert(obj.prototype);
//输出myFunc的函数代码，obj由myFunc构造出来的
alert(obj.constructor);
//输出true
alert(obj.constructor == myFunc);

//输出[object Object]，说明myFunc的原型是一个对象
alert(myFunc.prototype);
//输出function Function() { [native code] }，[native code]的意思是JavaScript引擎的内置函数
alert(myFunc.constructor);
//输出true，函数原型的构造器默认是该函数
alert(myFunc.prototype.constructor == myFunc);</pre>
<p>构造器与函数的概念是一致的，即代码1中，<strong>myFunc就是一个构造器</strong>，因为通过new myFunc()就可以构造出一个对象实例了。因此，&#8221;alert(obj.prototype)&#8221;输出undefined说明了<strong>对象实例是没有原型的</strong>，&#8221;alert(myFunc.prototype)&#8221;输出[object Object]说明了<strong>构造器有原型</strong>，而“obj.constructor==myFunc&#8221;返回true说明obj的构造器是myFunc。<br />
<span id="more-136"></span><br />
原型其实也是一个对象实例。再强调一下<strong>原型的含义</strong>是：如果构造器有个原型对象A，则由该构造器创建的实例(Object Instance)都必然复制于A，而且采用的读遍历机制复制的。读遍历复制的意思是：仅当写某个实例的成员时，将成员的信息复制到实例映像中。即当构造一个新的对象时，新对象里面的属性指向的是原型中的属性，读取对象实例的属性时，获取的是原型对象的属性值。而当对象实例对一个属性进行写操作时，才会将属性写到新对象实例的属性列表中。</p>
<p style="text-align: center;"><img class="size-full wp-image-142 aligncenter" title="prototype_build" src="http://blog.endlesscode.com/wp-content/uploads/2010/01/prototype_build.jpg" alt="prototype_build" width="563" height="187" /></p>
<p style="text-align: center;">图1 JavaScript使用读遍历机制实现的原型继承</p>
<p>代码2：</p>
<pre class="brush:javascript">Object.prototype.value = "abc";
var obj1 = new Object();
var obj2 = new Object();
obj2.value = 10;
//输出abc，读取的是原型Object中的value
alert(obj1.value);
//输出10，读取的是obj2成员列表中的value
alert(obj2.value);
//删除obj2中的value，即在obj2的成员列表中将value删除掉
delete obj2.value;
//输出abc，读取的是原型Object中的value
alert(obj2.value);</pre>
<p>图1是对代码2的描述，说明读遍历机制是如何在成员列表以至原型中管理对象成员的。只有对属性进行第一次写操作的时候，才会在对象的成员列表中添加该属性的记录。当obj1和obj2通过new来构造出来的时候，仍然是一个指向原型的引用，在操作过程中也没有与原型相同大小的对象实例创建出来。这样的读遍历就避免在创建新对象实例时可能的大量内存分配。当obj2.value属性被赋值为10的时候，obj2则在其成员表中添加了一个value成员，并赋值为10，这个成员表就是记录了obj2中发生了修改的成员名、值与类型。这张表是否与原型一致并不重要，只需要遵循两条规则：(1)保证在读取时被首先访问到。(2)如果在对象中没有指定的属性，则尝试遍历对象的整个原型链，直到原型为空或找到该属性。代码2中的delete操作是将obj2成员表中的value删除了，因此在读取obj2的value属性的时候就遍历到Object中读取。</p>
<p>函数的原型总是一个标准的、系统内置的Object()构造器的实例，不过该实例创建后constructor属性总先被赋值为当前的函数。</p>
<p>代码3：</p>
<pre class="brush:javascript">function MyObject() {
}

//显示true，表明原型的构造器总是指向函数自身的
alert(MyObject.prototype.constructor == MyObject);

//删除该成员
delete MyObject.prototype.constructor;

//删除操作使该成员指向了父代类原型中的值
//均显示为true
alert(MyObject.prototype.constructor == Object);
alert(MyObject.prototype.constructor == new Object().constructor);</pre>
<p>从代码3中可以看出，MyObject.prototype其实与一个普通对象&#8221;new Object()&#8221;并没有本质的区别，只是在创建时将constructor赋值为当前函数MyObject。然后，当一个函数的prototype有意义之后，它就摇身一变成了一个“构造器”，这时，如果用户试图用new运算符创建它的实例时，那么引擎就会再构造一个新的对象，并使这个新对象的原型链接向这个prototype属性就可以了。因此，<strong>函数与构造器并没有明显的界限</strong>。</p>
<p>一个构造器产生的实例，其<strong>constructor属性默认总是指向该构造器</strong>，而究其根源，则在于<strong>构造器（函数）的原型的constructor属性</strong>指向了构造器本身。<br />
代码4：</p>
<pre class="brush:javascript">function MyObject() {
}
var obj = new MyObject();
//输出为true，默认指向构造器
alert(obj.constructor == MyObject);
//输出为true，原型的构造器指向该构造器
alert(MyObject.prototype.constructor == MyObject);</pre>
<p>由此可见，JavaScript事实上已经为构造器维护了原型属性，因此我们可以通过实例的constructor属性来找到构造器，并进而找到它的原型“obj.constructor.prototype&#8221;。但是，如果我们把构造器的原型修改了的话，会出现什么情况呢？如代码5，我们把MyObjectEx的原型修改了。<br />
代码5：</p>
<pre class="brush:javascript">function MyObject() {
}
function MyObjectEx() {
}
MyObjectEx.prototype = new MyObject();
var obj1 = new MyObject();
var obj2 = new MyObjectEx();
alert(obj1.constructor == obj2.constructor);    //true
alert(MyObjectEx.prototype.constructor == MyObject.prototype.constructor);    //true
</pre>
<p>在代码5中，obj1和obj2是由不同的两个构造器产生的实例，分别是MyObject和MyObjectEx。然而，我们看到，代码5中的两个alert都会输出true，即是说，<strong>由两个不相同的构造器产生的实例（代码5中的MyObject和MyObjectEx），它们的constructor属性却指向了相同的构造器</strong>，是不是很诡异？这个正确是体现了原型继承中出出现的“原型复制”了。要注意，MyObjectEx的原型是由MyObject构造出来的对象实例，即obj1和obj2都是从MyObject原型中复制出来的对象，因此它们的constructor指向的都是MyObject。那么怎么解决这个问题？<br />
代码6：</p>
<pre class="brush:javascript">function MyObject() {
    this.constructor = arguments.callee; //arguments.callee为MyObject，正确维护constructor，以便回溯外部原型链
}
MyObject.prototype = new Object(); //人为构建外部原型链

function MyObjectEx() {
    this.constructor = arguments.callee; //正确维护constructor，以便回溯外部原型链
}
MyObjectEx.prototype = new MyObject(); //人为构建外部原型链

obj1 = new MyObjectEx();
obj2 = new MyObjectEx();</pre>
<p>代码6与代码5中的主要区别就是在于，在MyObjectEx的初始化中正确地维护了constructor属性，使当前的constructor属性指向了调用的构造器。代码6所描述的继承关系如图2：</p>
<p style="text-align: center; "><img class="size-full wp-image-145 aligncenter" title="proto" src="http://blog.endlesscode.com/wp-content/uploads/2010/01/proto.jpg" alt="proto" width="573" height="424" /></p>
<p style="text-align: center; ">图2 构造器原型链与内部原型链</p>
<p>其中有[proto]属性中一个对象的私有属性，用于正确维护对象的内部原型链，在Firefox中可以通过[__proto__]来访问，这个后面再讨论。我们可以看到MyObjectEx的构造器是MyObject的对象实例，而MyObject的构造器是Object的对象实例。<br />
接代码6：</p>
<pre class="brush:javascript">obj = new MyObject();
alert(obj.constructor === MyObject);    //true
alert(obj1.constructor === MyObjectEx);    //true
alert(obj.constructor === obj1.constructor);    //false</pre>
<p>可以看到，obj和obj1从不同的构造器产生的实例，其constructor属性已经能够正确地指向相应的构造器，这个是由于在对象实例初始化的时候的赋值语句&#8221;this.constructor = arguments.callee;&#8221;。你可能会疑问为什么不采用下面这种方式来实现：</p>
<pre class="brush:javascript">MyObjectEx.prototype = new MyObject();
MyObjectEx.prototype.constructor = MyObjectEx;</pre>
<p>这样虽然能使obj1和obj2的constructor属性正确地指向了MyObjectEx，但是，这样同时也使得MyObjectEx的原型对象（MyObject构造的实例）的constructor属性没法往父代原型追溯。因为当MyObjectEx的原型对象想通过constructor属性来获取到MyObject构造器时，会发现获取到的是MyObjectEx的构造器，而不是期待的MyObject的构造器。<br />
我们可以通过下面的语句来验证代码6是不是的确是如图2的关系链：</p>
<pre class="brush:javascript">alert(obj1.constructor === MyObjectEx); //true
alert(MyObjectEx.prototype instanceof MyObject); //true
alert(MyObjectEx.prototype.constructor === MyObject); //true
alert(MyObject.prototype instanceof Object); //true
alert(MyObject.prototype.constructor === Object); //true
alert(obj1.constructor.prototype.constructor.prototype.constructor === Object); //true，完成了所有的回溯</pre>
<p>好了，刚才上面提到了有一个不可访问的属性[proto]，这个属性是JavaScript引擎内部维护的原型链属性，这个属性在Firefox里面可以通过[__proto__]来访问的，一般情况下，[proto]属性指向的和prototype属性一样，指向的都是原型对象，两个有什么不同后面会有讲述。</p>
<pre class="brush:javascript">//输出都是true，在Firefox中
alert(obj.__proto__ instanceof Object);
alert(obj1.__proto__ instanceof MyObject);
alert(obj2.__proto__ instanceof MyObject);</pre>
<p>这个[proto]属性是JavaScript内部维护的，外部是不可访问的，由这个属性所维护的原型链为<strong>内部原型链</strong>，与由prototype和constructor维护的<strong>外部原型链</strong>。那么这两条原型链有什么区别呢？简单来说就是，<strong>通过prototype和constructor来维护的外部原型链是开发人员自己代码中回溯时用到的，而通过[proto]维护的内部原型链是JavaScript原型继承机制实现所需要的</strong>。具体来说，外部原型链就是做这种事：&#8221;alert(obj1.constructor.prototype.constructor.prototype.constructor === Object);&#8221;，也就是说当我们开发人员想要自己去回溯整个原型继承的结构链时，也只会在我们开发人员写代码时才出现通过prototype和constructor来访问外部原型链。而内部原型链，这个比较有意思，在［图1 JavaScript使用读遍历机制实现的原型继承］，我们看到，当我们访问一个对象实例的属性时，它如果发现在其成员列表中没有该属性，即会去访问原型的成员列表，把原型的默认值读取出来，也就是说，这个在原型链中回溯来查询成员属性的过程，只会在内部原型链中进行，这个过程是由JavaScript引擎自己去维护的，开发人员没法干涉。来看看代码，我觉得这个还是相当有意思的：<br />
接代码6：</p>
<pre class="brush:javascript">alert(obj.__proto__ instanceof Object);    //true
alert(obj1.__proto__ instanceof MyObject);    //true
alert(obj2.__proto__ instanceof MyObject);    //true
//按照上面所说的，在MyObjectEx的原型上添加了value的属性，那么在访问obj1和obj2的value属性时便会往原型中查找
MyObjectEx.prototype.value = "Hello World!";
//这里正确地输出"Hello World!"
alert(obj1.value);
//在此时，obj1和obj2都构造之后，我把原来的MyObjectEx的原型换了，变成MyObjectEx2
function MyObjectEx2() {}
MyObjectEx.prototype = new MyObjectEx2();
//这句究竟会输出什么呢？[Referece Error]还是？
alert(obj1.value);</pre>
<p>最后的1个alert输出的&#8221;Hello World!&#8221;，有意思吧。即使我在上面把MyObjectEx的原型对象改变成新的MyObjectEx2，但是在obj1和obj2中的[proto]属性依然指向的是原来的MyObject构造的对象实例，也就是说内部访问属性时是通过[proto]来回溯原型链的，而不是通过prototype的（而且对象实例也没有prototype属性），这个就是内部原型链体现的威力。</p>
<p>参考：</p>
<ul>
<li><a href="http://w3er.com/blog/2009/03/master-javascript-object-system/" target="_blank">JavaScript对象真经</a></li>
<li>《JavaScript语言精髓与编程实践》</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.endlesscode.com/2010/01/23/javascript-prototype-chain/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>浅谈JavaScript的闭包和作用域链</title>
		<link>http://blog.endlesscode.com/2010/01/20/javascript-closure-scope-chain/</link>
		<comments>http://blog.endlesscode.com/2010/01/20/javascript-closure-scope-chain/#comments</comments>
		<pubDate>Thu, 21 Jan 2010 02:14:47 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://blog.endlesscode.com/?p=102</guid>
		<description><![CDATA[闭包和作用域链是JavaScript中比较重要的概念，这两天翻阅了一些资料，总结了一下。首先，看看几段简单的代码。 代码1： var name = "stephenchan"; var age = 23; function myFunc() { alert(name); var name = "endlesscode"; alert(name); alert(age); alert(weight); } myFunc(); myFunc(); 上述代码1中，两次调用myFunc()的输出是一致的。可能你会认为输出是： stephenchan endlesscode 23 [Reference Error] 但是结果却是： 代码1输出： undefined endlesscode 23 [Reference Error] 代码2： var i &#8230; <a href="http://blog.endlesscode.com/2010/01/20/javascript-closure-scope-chain/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>闭包和作用域链是JavaScript中比较重要的概念，这两天翻阅了一些资料，总结了一下。首先，看看几段简单的代码。</p>
<p><strong>代码1：</strong></p>
<pre class="brush:javascript">var name = "stephenchan";
var age = 23;
function myFunc() {
    alert(name);
    var name = "endlesscode";
    alert(name);
    alert(age);
    alert(weight);
}
myFunc();
myFunc();</pre>
<p>上述代码1中，两次调用myFunc()的输出是一致的。可能你会认为输出是：</p>
<pre class="brush:javascript">stephenchan
endlesscode
23
[Reference Error]</pre>
<p>但是结果却是：</p>
<pre class="brush:plain">代码1输出：
undefined
endlesscode
23
[Reference Error]</pre>
<p><strong>代码2：</strong></p>
<pre class="brush:javascript">var i = 10;
function myFunc() {
    var i = 20;
    function innerFunc() {
		alert(i);
    }
    return innerFunc;
}
var func = myFunc();
func();</pre>
<p>上面的代码2会输出20，但为什么不输出10或者是输出undefined？</p>
<pre class="brush:plain">代码2输出：
20</pre>
<p><strong>代码3：</strong></p>
<pre class="brush:javascript">var name = "stephenchan";
function callMePlz() {
	alert(name);
}

function myFunc() {
	var name = "endlesscode";
	callMePlz();
}

myFunc();</pre>
<p>上面的代码3输出的会是endlesscode、stephenchan还是undefined？</p>
<pre class="brush:plain">代码3输出：
stephenchan</pre>
<p><span id="more-102"></span><br />
<strong>代码4：</strong></p>
<pre class="brush:javascript">function callMePlz() {
	var name = "stephenchan";
	var intro = function() {
		alert("I am " + name);
	}
	return intro;
}

function showMe(arg) {
	var name = arg;
	var func = callMePlz();
	func();
}
showMe("endlesscode");</pre>
<p>上面的代码4与代码3不同的是，从callMePlz返回的函数引用，然后再执行函数。</p>
<pre class="brush:plain">代码4输出：
I am stephenchan</pre>
<p><strong>代码5：</strong></p>
<pre class="brush:javascript">var name = "stephenchan";
function callMePlz() {
	var intro = function() {
		alert("I am " + name);
	}
	return intro;
}

function showMe(arg) {
	var name = arg;
	var func = callMePlz();
	func();
}
showMe("endlesscode");</pre>
<p>上面的代码5与代码4不同的是原来在callMePlz函数中的变量name在全局环境中声明了，但输出的结果是：</p>
<pre class="brush:plain">代码5输出：
I am stephenchan</pre>
<p>先不对上面的代码进行说明，讲述一下闭包和作用域链的概念。</p>
<p>闭包(closure)是什么？闭包与函数有着紧密的关系。“在JavaScript中，一个函数只是一段静态的代码、脚本文件，因此函数是一个代码书写时，以及编译期的、静态的概念；而闭包则是函数的代码在运行过程中的一个动态环境，是一个运行期的、动态的概念”。这是《JavaScript语言精髓和编程实践》中对函数和闭包的描述，实际上我们常说的闭包倒是可以表现为如上面代码2中的innerFunc一样，在myFunc的函数执行后返回的是一个在其内部定义的、外部可调用的函数引用，这个函数语言的特性在C和C++是没有的。为什么在myFunc结束之后innerFunc还能正常访问到myFunc里面的数据呢？这就涉及到函数执行环境与闭包的相关概念，闭包中所保留着函数运行的实例，环境以及作用域链等等，并在myFunc调用之后没有将函数实例直接丢弃，因此在调用innerFunc的时候能够引用到myFunc中声明的i。</p>
<p>作用域链(scope chain)是什么？顾名思义，就是由作用域组成的链，是一个类似链状的数据结构。作用域就是对上下文环境的数据描述。闭包和作用域链是紧密关系的，函数实例执行时的闭包是构成作用域链的基本元素。JavaScript代码在执行前会进行语法分析，在语法分析阶段，会记录全局环境中的变量声明和函数定义，构造函数的调用对象(Call Oject、Activation Object、Activate Object、活动对象，不同称呼罢了)和在全局环境下的作用域链。</p>
<p style="text-align: center; "><img class="aligncenter" style="border: 0px initial initial;" title="closure" src="http://blog.endlesscode.com/wp-content/uploads/2010/01/closure.jpg" alt="closure" width="466" height="290" /></p>
<p style="text-align: center;">图1</p>
<p>图1是《JavaScript语言精髓和编程实践》一书中对闭包相关元素的内部数据结构的描述。我们主要关注其中的ScriptObject，ScriptObject是对调用对象的一种描述。ScriptObject在语法分析阶段就已经构造好了，其中的varDecls是保存着函数中的变量声明，funcDecls保存着内部的函数声明。</p>
<p>在语法分析阶段，varDecls保存在函数中用var进行<strong>显示声明的局部变量</strong>，并且置默认值为undefined，这里就是在代码1中&#8221;alert(name)&#8221;输出为undefined的原因，由于myFunc在语法分析阶段就已经保留了标记符name在varDecls，在赋值语句&#8221;var name=&#8217;endlesscode&#8217;&#8221;执行之前name的值都是undefined，因此在&#8221;alert(name)&#8221;的时候就显示为undefined了。</p>
<p>而函数定义在语法分析阶段工作就稍微有点不同。在语法分析阶段，发现有函数定义的时候，除了记录函数的声明外，还会创建一个函数对象，并将当前的作用域链赋值给此函数对象的[[scope]]属性（这个属性是JavaScript引擎内部维护的，但是Firefox却是可以通过私有属性__parent__来访问它），这里要注意的是在语法分析阶段将作用域链赋值给[[scope]]属性，而不是在执行阶段。如果是在全局环境下，但当前的作用域链为只有一个元素，就是全局的调用对象（Windows Object, Global Object，不同称呼罢了）。这就是为什么在《JavaScript权威指南》中提到“JavaScript中的函数运行在它们被定义的作用域里，而不是它们被执行的作用域里。”</p>
<p>下面以一段代码的大概处理流程来进行说明：</p>
<pre class="brush:javascript">var outerVar1 = "var in global code";
function outerFunc(arg1, arg2) {
    var innerVar1 = "var in function code";
    function innerFunc() { return outerVar1 + "-" + innerVar1 + "-" + (arg1 + arg2); }
    return innerFunc();
}
var outerVar2 = outerFunc(10, 20);</pre>
<p>执行处理过程大致如下：</p>
<ol>
<li>引擎启动，初始化Global Object，即window对象，全局的调用对象，建立作用域链，假设为scope_1，作用域链中只包含全局的上下文环境，即Global Object。</li>
<li>语法分析阶段，扫描JavaScript代码，获取代码中变量和函数定义，其扫描过程如下：
<ol>
<li>发现变量outerVar1，在Global Object的varDecls中添加outerVar1属性，值为undefined。</li>
<li>发现函数outerFunc的定义，在Global Object的funcDecls中添加outerFunc，并创建函数对象（这里应该创建的是函数的原型对象），将scope_1传递给outerFunc的函数对象，即outerFunc内部的[[scope]]属性。另外注意，创建过程并不会对函数体中的JavaScript代码做特殊处理，可以理解为只是将函数JavaScript代码保存中函数对象的内部属性上，在函数执行时再做进一步处理。也就是说，这一步大概处理的就是记录函数定义，赋值[[scope]]属性记录当前定义的作用域，而没有进一步对outerFunc里面的代码进行进一步的语法分析。</li>
<li>发现变量outerVar2，在Global Object中的varDecls中添加属性，值为undefined。</li>
</ol>
</li>
<li>全局环境下语法分析结束，执行outerVar1赋值语句，赋值为&#8221;<span style="font-family: Consolas, Monaco, 'Courier New', Courier, monospace; line-height: 18px; font-size: 12px; white-space: pre; background-color: #ffffff;">var in global code&#8221;。</span></li>
<li><span style="font-family: Consolas, Monaco, 'Courier New', Courier, monospace;"><span style="line-height: 18px; white-space: pre; font-size: small; background-color: #ffffff;">执行outerFunc，获取返回值。</span></span>
<ol>
<li>创建调用对象，假设为avt_obj_1。同时将avt_obj_1链接起outerFunc的[[scope]]属性，构成一个新的作用域链，假设为scope_2，scope_2中的第一个对象为act_obj_1，act_obj_1指向scope_1。</li>
<li>处理参数列表，在act_obj_1中设置属性arg1、arg2，值分别为10和20。创建arguments对象并进行设置，将arguments设置为act_obj_1的属性。</li>
<li>对outerFunc函数体进行语法分析，注意这里在全局语法分析的时候并没有对outerFunc函数体进行语法分析：
<ol>
<li>发现变量innerVar1，在act_obj_1中的varDecls添加innerVar1属性，值为undefined。</li>
<li>&lt; 发现函数innerFunc的定义，使用这个定义创建函数对象，并将scope_2传递给innerFunc，作为innerFunc的[[scope]]属性，在act_obj_1的funcDecls添加innerFunc。</li>
</ol>
</li>
<li>outerFunc函数语法分析结束，执行innerVar1赋值语句，赋值为&#8221;var in function code&#8221;。</li>
<li>执行innerFunc，执行函数的处理流程是一致的：
<ol>
<li>创建调用对象，假设为act_obj_2；同时将avt_obj_2链接起innerFunc[[scope]]属性，构成一个新的作用域链，假设为scope_3，scope_3中的第一个对象为act_obj_2，act_obj_2指向scope_2。</li>
<li>处理参数列表，因为innerFunc没有参数，所以只需要创建arguments对象并设置为act_obj_2的属性。</li>
<li>对innerFunc进行语法分析，识别变量和函数，但没有发现变量定义和函数声明。</li>
<li>执行innerFunc函数。对任何一个变量引用，从scope_3开始进行链式搜索，以scope_3-&gt;scope_2-&gt;scope_1的顺序进行搜索，结果发现outerVar1在scope_1中的Global Object发现；innerVar1、arg1、arg2在scope_2中的act_obj_1中找到。</li>
<li>检查scope_3和act_obj_2的引用，发现没有其他引用，则丢弃，让引擎进行垃圾回收。</li>
<li>返回innerFunc执行的值。</li>
</ol>
</li>
<li><span style="font-family: Consolas, Monaco, 'Courier New', Courier, monospace;"><span style="line-height: 18px; white-space: pre;">检查没有对act_obj_1和scope_2的引用，则丢弃act_obj_1和scope_2。</span></span></li>
<li><span style="font-family: Consolas, Monaco, 'Courier New', Courier, monospace;"><span style="line-height: 18px; white-space: pre;">返回结果。</span></span></li>
</ol>
</li>
<li><span style="font-family: Consolas, Monaco, 'Courier New', Courier, monospace;"><span style="line-height: 18px; white-space: pre; background-color: #ffffff;">将outerFunc的返回结果赋值给outerVar2。</span></span></li>
</ol>
<p>我们拿代码4的例子再对作用域链进行简单的分析：<br />
<strong>代码4：</strong></p>
<pre class="brush:javascript">function callMePlz() {
	var name = "stephenchan";
	var intro = function() {
		alert("I am " + name);
	}
	return intro;
}

function showMe(arg) {
	var name = arg;
	var func = callMePlz();
	func();
}
showMe("endlesscode");</pre>
<p>假如全局的语法分析已经结束，已经开始执行&#8221;showMe(&#8216;endlesscode&#8217;)&#8221;了。在进入执行showMe的执行上下文时，我们可以看到&#8221;showMe&#8221;函数中[[scope]]属性记录中的作用域链为：</p>
<pre class="brush:plain">[[scope]] = [
    {//Global Object，因为在全局没有var声明的变量，因此就没有列出来
    document : ...,
    location : ...
    }
]</pre>
<p>创建showMe的调用对象后，则新的作用域链为showMe的调用对象和全局调用对象组成：</p>
<pre class="brush:plain">[scope chain] = [
    {//showme_activation_obj
        name : undefined,
        func : undefined,
        arg : "endlesscode",
        arguments : ...
     },
    {//Global Object，因为在全局没有var声明的变量，因此就没有列出来
    document : ...,
    location : ...
    }
]</pre>
<p>也就是&#8221;showMe调用对象-&gt;Global调用对象&#8221;这样的链式关系。接着，忽略showMe函数中语法分析等过程，到执行callMePlz()函数时，callMePlz函数的[[scope]]属性为</p>
<pre class="brush:plain">[[scope]] = [
    {//Global Object，因为在全局没有var声明的变量，因此就没有列出来
    document : ...,
    location : ...
    }
]</pre>
<p>callMePlz函数的[[scope]]属性指示的作用域链也只包括了全局调用对象，因为callMePlz也是在全局环境下定义的。创建callMePlz的调用对象后，则新的作用域链为callMePlz的调用对象和全局调用对象组成：</p>
<pre class="brush:plain">[scope chain] = [
    {//callmeplz_activation_obj
        name : undefined,
        intro : undefined,
        arguments : ...
     },
    {//Global Object，因为在全局没有var声明的变量，因此就没有列出来
    document : ...,
    location : ...
    }
]</pre>
<p>也就是&#8221;callMePlz调用对象-&gt;Global调用对象&#8221;这样的链式关系。可以看到，在callMePlz的作用域链中，并没有包括showMe的调用对象。当callMePlz进行语法分析的时候，找到intro函数时，将intro函数的[[scope]]属性赋值为：</p>
<pre class="brush:plain">[scope chain] = [
    {//callmeplz_activation_obj
        name : undefined,   //这里还是undefined，当语法分析结束，执行callMePlz时，这里就赋值为"stephenchan"
        intro : undefined,
        arguments : ...
     },
    {//Global Object，因为在全局没有var声明的变量，因此就没有列出来
    document : ...,
    location : ...
    }
]</pre>
<p>callMePlz返回的是intro函数对象的引用，当在showMe函数中执行intro函数时，创建intro函数的调用对象，此时intro函数的作用域链为：</p>
<pre class="brush:plain">[scope chain] = [
    {//intro_activation_obj
        arguments : ...
     },
    {//callmeplz_activation_obj
        name : undefined,   //这里还是undefined，当语法分析结束，执行callMePlz时，这里就赋值为"stephenchan"
        intro : undefined,
        arguments : ...
     },
    {//Global Object，因为在全局没有var声明的变量，因此就没有列出来
    document : ...,
    location : ...
    }
]</pre>
<p>由于在intro函数中没有声明变量和函数，所以看到的也只是一些内置的属性成员，此时intro函数的作用域链则为：&#8221;intro调用对象-&gt;callMePlz调用对象-&gt;Global调用对象&#8221;，因此，当执行intro函数时，则以&#8221;intro调用对象-&gt;callMePlz调用对象-&gt;Global调用对象&#8221;的顺序去搜索&#8221;name&#8221;变量，发现在callMePlz调用对象上找到了，因此在代码4中输出的是&#8221;I am stephenchan&#8221;而不是&#8221;I am endlesscode&#8221;。</p>
<p>以上面的分析方法来分析上述的其他代码，就容易理解其输出了。</p>
<p>对于Eval函数的环境中，进入Eval函数执行时会创建一个新的作用域链，至于作用域链的内容，在IE和Mozilla中会稍有不同。</p>
<pre class="brush:javascript">var i = 100;
function myFunc(ctx) {
    var i = "test";
    eval('i = "hello world!"');
}
myFunc();
alert(i);</pre>
<p>上面的代码，毫无疑问，在IE和Mozilla都会显示100，因为eval代码执行的上下文环境是myFunc函数中的i，而非全局中的i。然后，再看下面代码：</p>
<pre class="brush:javascript">var i = 100;
function myFunc(ctx) {
    var i = "test";
    window.eval('i = "hello world!"');
}
myFunc();
alert(i);</pre>
<p>上面代码中，输出的还是100吗？还是&#8221;hello world!&#8221;呢？这取决于不同的浏览器，在IE中，输出的結果依然100，而在Mozilla中，输出却为&#8221;hello world!&#8221;，因为在IE中，eval函数作为全局对象Global Object的函数，只能获得访问到其执行环境下的作用域链，而不能获得全局作用域链的能力。而在Mozilla中，eval函数是所有对象的一个方法，而并非只是Global Object的方法，因此以window.eval的方式调用，得到的作用域链则是全局环境下的作用链，因此直接将全局环境下的i进行了修改。<br />
另外，函数闭包内的标识符系统有优先顺序，其优先级从高到低为：this &gt; 局部变量(varDecls) &gt; 函数形式参数名(argsName) &gt; arguments关键字 &gt; 函数名(funcNames)。</p>
<pre class="brush:javascript">//输出'hi'，说明argsName &gt; funcNames。
function foo(foo) {
    alert(foo);
}
foo('hi');

//输出100的类型"number"，说明argsName &gt; arguments。
function foo2(arguments) {
    alert(typeof arguments);
}
foo2（100）;

//输出arguments的类型为'object‘，说明arguments &gt; funcNames。
function arguments() {
    alert(typeof arguments);
}
arguments();

//输出'test'，形式参数名与未赋值局部变量重复时，取形式参数值。
function foo3(str) {
    var str;
    alert(str);
}
foo3('test');

//输出'member'，形式参数与有值的局部变量重复时，取局部变量。
function foo4(str) {
    var str = 'member';
    alert(str);
}
foo4('test');</pre>
<p>参考：</p>
<ul>
<li><span style="background-color: #ffffff;"><a href="http://www.cnblogs.com/RicCC/archive/2008/02/15/JavaScript-Object-Model-Execution-Model.html" target="_blank">JavaScript对象模型-执行模型</a></span></li>
<li><a href="http://www.laruence.com/2009/05/28/863.html" target="_blank">JavaScript作用域的原理</a></li>
<li><a href="http://www.felixwoo.com/archives/247">深入理解JavaScript闭包(closure)</a></li>
<li>《JavaScript语言精髓与编程实践》</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.endlesscode.com/2010/01/20/javascript-closure-scope-chain/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>《JavaScript语言精髓与编程实践》读书拾遗-非函数式语言特性</title>
		<link>http://blog.endlesscode.com/2009/12/28/javascript-nonfunction-feature/</link>
		<comments>http://blog.endlesscode.com/2009/12/28/javascript-nonfunction-feature/#comments</comments>
		<pubDate>Mon, 28 Dec 2009 18:32:25 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://blog.endlesscode.com/?p=68</guid>
		<description><![CDATA[变量的生存周期是指它何时被创建和被释放。在JavaScript中，一个变量的创建是在：引擎做语法分析时，发现显式声明；引擎做代码执行，发现试图写（例如赋值）一个未被创建的变量时。而变量的释放则是在：引擎执行到函数结束/退出操作时，将清除函数内的未被引用的变量；引擎执行到全局的代码块终结或引擎卸载和重载入时，将清除全局的亦是和数据的引用。 变量作用域讨论的是“在形式上这个变量能在哪个范围内存取到”。 对于具名函数的声明来说，抛开语法解析导致的问题不讲，一个具名函数是完全等同于一个匿名函数赋值给一个已经声明的变量标识符。 在JavaScript中，“空对象(null)“是作为一个保留字存在的。null不是“空的对象”，而是代表这样的一个对象：属性对象类型；对象是空值的。因为它是对象类型，所以用(typeof null)会返回object，甚至可以用for&#8230;in&#8230;去列举它，只不过因为它是空值，所以没有任何方法和属性，因而列举不到内容。 所谓“空的对象”，是一个标准的、通过Object()构造的对象实例，即通过obj = new Object()；或者obj = { }；空的对象具有“对象”的一切特性，可以存取预定义属性和方法(toString、valueOf等)。 对象只有“构造自某个原型”的说法，而不存在“持有（或拥有）某个原型”的说法。原型其实也是一个对象实例。原型的含义是指：如果构造器有一个原型对象A，则由该构造器创建的实例都必然复制自A。 JavaScript在构造对象的时候，采用的是读遍历的机制，即把写复制的粒度从原型变成了成员。这种方法的特点是：仅当写某个实例的成员时，将成员的信息复制到实例的的映像中，而并不是在刚构造时就从原型中复制全部成员。 在读遍历的机制下，所有的对象实例需要维护一张成员列表，这个成员列表指向在对象实例中发生了修改的成员名、值与类型。这张表是否与原型一致并不重要，只需要遵循两条规则：保证在读取时首先被访问到；如果在对象中没有指定属性，则尝试遍历对象的整个原型链，直到原型为空（null）或找到该属性。存取实例中的属性，比存取原型中的属性效率要高，因为少了一个指针访问。 实例创建后constructor属性总先被赋值为当前函数，当用delete删除constructor属性时，constructor则会指向父类的函数。 由构造过程可以了解到，JavaScript中的对象实例本质上只是“一个指向其原型的，并持有一个属性列表的结构”。对象原型所具有的基本性质有：toString、toLocaleString、valueOf、construtor、propertyIsEnumerable、hasOwnProperty、isPrototypeof。除了上述普通对象的成员之外，还具有几个特别的、属于函数类型对象的成员：call、apply、caller、arguments、length、prototype。 在JavaScript中，基于“JS变量作用域”来实现封装性时，只能实现public和private这两种封装性。 function MyObject() { /* 私有变量和函数 */ var data = 100; function _run(v) { alert(v); } /* 公开属性和方法 */ this.value = "The data &#8230; <a href="http://blog.endlesscode.com/2009/12/28/javascript-nonfunction-feature/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<ul>
<li>变量的生存周期是指它何时被创建和被释放。在JavaScript中，一个变量的创建是在：引擎做<strong>语法分析</strong>时，发现<strong>显式声明</strong>；引擎做<strong>代码执行</strong>，发现试图写（例如赋值）一个未被创建的变量时。而变量的释放则是在：引擎执行到函数结束/退出操作时，将清除函数内的未被引用的变量；引擎执行到全局的代码块终结或引擎卸载和重载入时，将清除全局的亦是和数据的引用。</li>
<li>变量作用域讨论的是“在形式上这个变量能在哪个范围内存取到”。</li>
<li>对于具名函数的声明来说，抛开语法解析导致的问题不讲，一个具名函数是完全等同于一个匿名函数赋值给一个已经声明的变量标识符。</li>
<li>在JavaScript中，“空对象(null)“是作为一个保留字存在的。null不是“空的对象”，而是代表这样的一个对象：属性对象类型；对象是空值的。因为它是对象类型，所以用(typeof null)会返回object，甚至可以用for&#8230;in&#8230;去列举它，只不过因为它是空值，所以没有任何方法和属性，因而列举不到内容。</li>
<li>所谓“空的对象”，是一个标准的、通过Object()构造的对象实例，即通过obj = new Object()；或者obj = { }；空的对象具有“对象”的一切特性，可以存取预定义属性和方法(toString、valueOf等)。</li>
<li>对象只有“构造自某个原型”的说法，而不存在“持有（或拥有）某个原型”的说法。原型其实也是一个对象实例。原型的含义是指：如果构造器有一个原型对象A，则由该构造器创建的实例都必然复制自A。</li>
<li>JavaScript在构造对象的时候，采用的是读遍历的机制，即把写复制的粒度从原型变成了成员。这种方法的特点是：仅当写某个实例的成员时，将成员的信息复制到实例的的映像中，而并不是在刚构造时就从原型中复制全部成员。</li>
<li>在读遍历的机制下，所有的对象实例需要维护一张成员列表，这个成员列表指向在对象实例中发生了修改的成员名、值与类型。这张表是否与原型一致并不重要，只需要遵循两条规则：保证在读取时首先被访问到；如果在对象中没有指定属性，则尝试遍历对象的整个原型链，直到原型为空（null）或找到该属性。存取实例中的属性，比存取原型中的属性效率要高，因为少了一个指针访问。</li>
<li>实例创建后constructor属性总先被赋值为当前函数，当用delete删除constructor属性时，constructor则会指向父类的函数。</li>
<p><span id="more-68"></span></p>
<li>由构造过程可以了解到，JavaScript中的对象实例本质上只是“一个指向其原型的，并持有一个属性列表的结构”。对象原型所具有的基本性质有：toString、toLocaleString、valueOf、construtor、propertyIsEnumerable、hasOwnProperty、isPrototypeof。除了上述普通对象的成员之外，还具有几个特别的、属于函数类型对象的成员：call、apply、caller、arguments、length、prototype。</li>
<li>在JavaScript中，基于“JS变量作用域”来实现封装性时，只能实现public和private这两种封装性。
<pre class="js">function MyObject() {
    /* 私有变量和函数 */
    var data = 100;
    function _run(v) {
        alert(v);
    }

    /* 公开属性和方法 */
    this.value = "The data is ...";
    this.run = function() { _run(this.value + data); }
}</pre>
</li>
<li>JavaScript是弱类型的，通过typeof运算考察变量时，它要么是对象(object)，要么是非对象(number, undefined, string等)，绝不存在“像是某个对象或者某个类”这样的多态问题。</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://blog.endlesscode.com/2009/12/28/javascript-nonfunction-feature/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>《JavaScript语言精髓与编程实践》读书拾遗-JavaScript语法</title>
		<link>http://blog.endlesscode.com/2009/12/28/javascript-grammar/</link>
		<comments>http://blog.endlesscode.com/2009/12/28/javascript-grammar/#comments</comments>
		<pubDate>Mon, 28 Dec 2009 18:32:09 +0000</pubDate>
		<dc:creator>Stephen</dc:creator>
				<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://blog.endlesscode.com/?p=57</guid>
		<description><![CDATA[JavaScript的6种基本数据类型undefined(未声明的变量，或者声明过但未赋值的变量的值，会是undefined。也可以显式或隐式地给一个变量赋值为undefined)，string(不能直接读取或修改字符串中的单一字符)，number，boolean，function，object。 NaN值，与自身并不等值，也不全等。 在早期Netscape的JavaScript中允许出现非Unicode字符，但现在ECMA标准统一要求JavaScript中的字符串必须是Unicode字符序列。 当一个直接量被识别为十进制整数时，它内部的存放格式可能是浮点数，也可能整型数，这取决于不同引擎的实现，因此不能指望JavaScript中的整型数会有较高的运算性能。 通过rx=/abcd\n\r/gi的直接量方式创建正则表达式对象，其中的转义字符是不能自动转义的，但通过rx=new RegExp(&#8220;abcd\n\r&#8221;,&#8221;gi&#8221;)的字符串创建正则表达式对象方式，其中的转义字符则会被自动转义，因此要在字符串中增加转义字符rx=new RegExp(&#8220;abcd\\n\\r&#8221;,&#8221;gi&#8221;)。 JavaScript中单词形式的运算符：typeof(取变量或值的类型)、void(运算表达式并忽略值，运算返回undefined)、new(创建指定类的对象实例)、in(检查对象属性)、instanceof(检查变量是否指定类的实例)、delete(删除实例属性)。 &#8220;===&#8221;和&#8221;!==&#8221;比较两个表达式，看是否具有相等的值或相同的数据类型。 JavaScript中，赋值是一个运算，而不是一个語句。 JavaScript中只有一种方法来完成函数调用，即在函数后紧临函数调用运算符&#8221;()&#8221;，这个运算符被解释为两个含义：使函数得以执行；从左到右运算并传入&#8221;( )&#8221;内的参数序列。 当語句位于以下几种情况之一时，可以省略分号：一个文本行或整个文本文件的末尾；在語法分隔符之前(如复合語句的大括号&#8221;}&#8221;)；在复合語句的大括号&#8221;}&#8221;之后。 語句的返回值由最后的一个子句或表达式的值决定，即使不返回值，也会返回undefined。 没有引用的匿名函数调用方法(1)：(function() { /*func body*/}()); 此为用强制运算符使函数调用运算得以执行。 没有引用的匿名函数调用方法(2)：(function() { /*func body*/})(); 此为用强制运算符运算“函数直接量声明”这个表达式，并返回一个函数自身的引用，然后通过函数调用运算符&#8221;()&#8221;来操作这个函数引用。 没有引用的匿名函数调用方法(3)：void function() { /*func body*/ }(); 此为调用函数并忽略返回值。 JavaScript中的标签就是一个标识符。标签可以与变量重名而互不影响，因为它是另一种独立的語法元素（即不是变量，也不是类型），其作用是指示“标签化語句”。 break子句不但可以使用在循环与条件分支内部，也可以使用在标签化語句的内部(break a_label)。 continue后面也可以带一个标签，但continue不允许跳转到&#8221;当前/外层的单个循环語句的起始&#8221;之外的其他任何地方。 try{ tryStatements } catch(exception) { &#8230; <a href="http://blog.endlesscode.com/2009/12/28/javascript-grammar/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<ul>
<li>JavaScript的6种基本数据类型undefined(未声明的变量，或者声明过但未赋值的变量的值，会是undefined。也可以显式或隐式地给一个变量赋值为undefined)，string(不能直接读取或修改字符串中的单一字符)，number，boolean，function，object。</li>
<li>NaN值，与自身并不等值，也不全等。</li>
<li>在早期Netscape的JavaScript中允许出现非Unicode字符，但现在ECMA标准统一要求JavaScript中的字符串必须是Unicode字符序列。</li>
<li>当一个直接量被识别为十进制整数时，它内部的存放格式可能是浮点数，也可能整型数，这取决于不同引擎的实现，因此不能指望JavaScript中的整型数会有较高的运算性能。</li>
<li>通过rx=/abcd\n\r/gi的直接量方式创建正则表达式对象，其中的转义字符是不能自动转义的，但通过rx=new RegExp(&#8220;abcd\n\r&#8221;,&#8221;gi&#8221;)的字符串创建正则表达式对象方式，其中的转义字符则会被自动转义，因此要在字符串中增加转义字符rx=new RegExp(&#8220;abcd\\n\\r&#8221;,&#8221;gi&#8221;)。</li>
<li>JavaScript中单词形式的运算符：typeof(取变量或值的类型)、void(运算表达式并忽略值，运算返回undefined)、new(创建指定类的对象实例)、in(检查对象属性)、instanceof(检查变量是否指定类的实例)、delete(删除实例属性)。</li>
<li>&#8220;===&#8221;和&#8221;!==&#8221;比较两个表达式，看是否具有相等的值或相同的数据类型。</li>
<li>JavaScript中，赋值是一个运算，而不是一个語句。</li>
<li>JavaScript中只有一种方法来完成函数调用，即在函数后紧临函数调用运算符&#8221;()&#8221;，这个运算符被解释为两个含义：使函数得以执行；从左到右运算并传入&#8221;( )&#8221;内的参数序列。</li>
<li>当語句位于以下几种情况之一时，可以省略分号：一个文本行或整个文本文件的末尾；在語法分隔符之前(如复合語句的大括号&#8221;}&#8221;)；在复合語句的大括号&#8221;}&#8221;之后。</li>
<li>語句的返回值由最后的一个子句或表达式的值决定，即使不返回值，也会返回undefined。</li>
<li>没有引用的匿名函数调用方法(1)：<strong>(</strong>function<strong>()</strong> { /*func body*/}<strong>())</strong>; 此为用强制运算符使函数调用运算得以执行。</li>
<p><span id="more-57"></span></p>
<li>没有引用的匿名函数调用方法(2)：<strong>(</strong>function<strong>()</strong> { /*func body*/}<strong>)()</strong>; 此为用强制运算符运算“函数直接量声明”这个表达式，并返回一个函数自身的引用，然后通过函数调用运算符&#8221;()&#8221;来操作这个函数引用。</li>
<li>没有引用的匿名函数调用方法(3)：void function<strong>()</strong> { /*func body*/ }<strong>()</strong>; 此为调用函数并忽略返回值。</li>
<li>JavaScript中的标签就是一个标识符。标签可以与变量重名而互不影响，因为它是另一种独立的語法元素（即不是变量，也不是类型），其作用是指示“标签化語句”。</li>
<li>break子句不但可以使用在循环与条件分支内部，也可以使用在标签化語句的内部(break a_label)。</li>
<li>continue后面也可以带一个标签，但continue不允许跳转到&#8221;当前/外层的单个循环語句的起始&#8221;之外的其他任何地方。</li>
<li>try{ tryStatements } catch(exception) { catchStatements } finally { finallyStatements };其中，finally{&#8230;}語句块的一个重要之处在于它“总是在try/catch块退出之前被执行“，无论在try/catch块中用return/break等退出时，总会执行finally块的代码再退出。</li>
<li>通过&#8221;obj = new constructor;&#8221;与&#8221;obj = new constructor();&#8221;创建实例是一致的，实例创建时需要使用一个函数作为“构造器”，但我们不能认为constructor后面的括号就是函数调用的括号。</li>
<li>对象直接量的声明&#8221;obj = { propertyName: expression[,...] }比构造函数来得简单方便，这里的propertyName可以用字符串表示，也可以只是一个标识符。因为这是語句語法，所以我们通常都用标识符，只有在特殊的情况下，才使用它的字符串格式，特殊的情况指：使用的标识符不满足JavaScript对标识符的规则；特殊的、强调的属性名。</li>
<li>对象成员可以通过for&#8230;in&#8230;来列举，需要强调的是可以列举的是“显式的成员名”，其原因在于JavaScript约定了一些隐含的成员名称，例如所有对象都应该具有的&#8221;toString&#8221;方法。这些名称在for&#8230;in&#8230;語句中不会被列举出来。对于一些引擎来说，这些隐含的成员名称总是不被列举（例如在JScript引擎中）；而对于另一些引擎中，只要覆盖、重写这个名称，它就可以被列举出来了（例如在SpiderMonkey）。因此在跨引擎的设计中，我们并不能依赖于for&#8230;in&#8230;語句来获取对象成员名称。</li>
<li>可以用delete来删除一个不需要的对象属性，delete obj.property，以使其不能被for&#8230;in&#8230;語句列举。大多数情况下成员都能被删除，包括对象成员和数组元素，甚至也包括全局对象Global的成员(delete isNaN)。但不能删除的有：用var声明的变量；直接继承自原型的成员。delete不能删除继承自原型的值，但如果修改了这个成员的值，你仍然可以删除它，这将使它恢复到原型的值。关于这一点的真相是：delete运算事实上是删除了实例的成员表中的值。如果真的需要删除该属性，你只能对原型实例进行操作，这样的话会直接影响到这个类构造的所有实例。</li>
<li>JavaScript的一些官方文档中提及delete仅在删除一个不能删除的成员时，才会返回false。而其他情况下——例如删除不存在的成员，或者继承自父代类/原型的成员，都应该返回true。这种因“不能删除成员”而返回false的情况不多，大概有Function对象的length、prototype、arguments等极少数的几个——而且这还依赖不同的脚本引擎，例如在Mozilla中arguments就是可以删除的。</li>
<li>按照JavaScript语言的约定，取一个“不存在的属性”的值并不会导致异常，而是返回&#8221;undefined&#8221;，而&#8221;undefined&#8221;可以被类型转换为if語句所需的布尔值&#8221;false&#8221;。</li>
<li>instanceof运算符将会检测类的继承关系。因此一个子类的实例，在对祖先类做instanceof运算时，仍会得到true。</li>
<li>对象成员是否能被列举，称为成员的可列举性。当某个对象成员不存在或它不可列举时，则对该成员调用propertyIsEnumerable()方法将返回false(obj.propertyIsEnumerable(&#8216;propertyName&#8217;))。比较常见的情况是：JavaScript对象的内置成员不能被列举。这种情况下，可以用&#8221;in&#8221;运算检测到该成员，但不能用&#8221;for&#8230;in&#8230;&#8221;語句来列举它。</li>
<li>原型链/父代类成员也是可以被&#8221;for&#8230;in&#8230;&#8221;語句列举的，但它的propertyIsEnumerable()却是false，即propertyIsEnumerable()被实现为“只检测对象的非（自原型链继承而来的）继承属性。</li>
<li>括号&#8221;( )&#8221;的二义性：
<ul>
<li>typeof作为运算，却可以这样调用typeof(123)。</li>
<li>声明函数时，用作参数表。</li>
<li>在with、for、if、while和do&#8230;while等語句，以及catch()等子句中用来作为限定表达式的词法元素，在if、while等語句中括号会有“将表达式結果转换为布尔值”的副作用。</li>
<li>括号&#8221;( )&#8221;用于强制表达式运算，改变优先级。</li>
<li>作为函数/方法调用运算符。</li>
</ul>
</li>
<li>大括号&#8221;{ }&#8221;的二义性：
<ul>
<li>表示“复合語句”。</li>
<li>对象直接量创建。这其中会出现歧义，如eval(&#8216;if (true) { entry : 1 }&#8217;)中，&#8217;{ entry : 1 }&#8217;这部分应该是作为创建的对象还是作为对象返回呢？JavaScript对此作出的解释为“語句优先”，即eval返回的是１，而不是对象。</li>
<li>用于函数直接声明时的語法符号。</li>
<li>大括号也是结构化异常处理的語法符号。之所以是异常处理的語法符号而不是复合語句，是因为如果它是复合語句的語法标识符，那么它必然是可以用单行語句来替代的，但如果在异常处理中用单行語句，则会出现語法错误。</li>
</ul>
</li>
<li>逗号&#8221;,&#8221;的二义性：
<ul>
<li>語法分隔符，如数组成员声明，var变量创建。</li>
<li>连续运算符。</li>
</ul>
</li>
<li>方括号&#8221;[ ]&#8220;的二义性：
<ul>
<li>数组声明，a = [ [1][1] ] =&gt; a = [ undefined ]</li>
<li>下标存取</li>
<li>对象成员存取</li>
</ul>
</li>
</ul>
<p><img id="myFxSearchImg" style="border: medium none; position: absolute; z-index: 2147483647; opacity: 0.6; display: none;" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAADsElEQVR4nK2VTW9VVRSGn33OPgWpYLARbKWhQlCHTogoSkjEkQwclEQcNJEwlfgD/AM6NBo1xjhx5LyJ0cYEDHGkJqhtBGKUpm3SFii3vb2956wPB/t+9raEgSs52fuus89613rftdcNH8/c9q9++oe/Vzb5P+3McyNcfm2CcPj9af9w6gwjTwzvethx3Bx3x8xwd1wNM8dMcTNUHTfFLPnX6nVmZpeIYwf3cWD/PhbrvlPkblAzVFurKS6GmmGqqComaS+qmBoTI0Ncu3mXuGvWnrJ+ZSxweDgnkHf8ndVTdbiT3M7cQp2Z31dRTecHAfqydp4ejhwazh6Zezfnu98E1WIQwB3crEuJ2Y45PBTAQUVR9X4At66AppoEVO1Q8sgAOKJJjw6Am6OquDmvHskZ3R87gW+vlHz98zpmiqphkkRVbQtsfPTOC30lJKFbFTgp83bWh7Zx/uX1B6w3hI3NkkZTqEpBRDBRzG2AQHcwcYwEkOGkTERREbLQ/8HxJwuW7zdYrzfZ2iopy4qqEspKaDYravVm33k1R91Q69FA1VBRzFIVvXbx5AgXT44A8MWP81yfu0utIR2aVK3vfCnGrcUNxp8a7gKYKiLCvY2SUvo/aNtnM3e49ucK9S3p0aDdaT0UAVsKi2tVi6IWwNL9JvdqTdihaz79/l+u/rHMxmaJVMLkS2OoKKLWacdeE3IsSxctc2D5Qcl6vUlVVgNt+fkPPcFFmTw1xruvT7SCd7nuVhDQvECzJH90h0azRKoKFRkAmP5lKTWAGRdefoZL554FQNUxB92WvYeA5UN4PtSqwB2phKqsqMpBgAunRhFR3j49zuU3jnX8k6fHEQKXzh1jbmGDuYU6s4t1rt6socUeLLZHhYO2AHSHmzt19ihTZ48O8Hzl/AmunD/BjTvrvPfNX3hWsNpwJCvwYm+ngug4UilSCSq6k8YPtxDwfA+WRawIWFbgscDiULcCEaWqBFOlrLazurupOSHLqGnEKJAY8TwBEHumqUirAjNm52vEPPRV4p01XXMPAQhUBjcWm9QZwijwokgAeYHlHYA06KR1cT6ZvoV56pDUJQEjw0KeaMgj1hPEY4vz2A4eW0/e1qA7KtQdsxTYAG0H3iG4xyK1Y+xm7XmEPOJZDiENzLi2WZHngeOjj2Pe+sMg4GRYyLAsx7ME4FnsyTD9pr0PEc8zPGRAwKXBkYOPEd96cZRvf11g9MDe7e3R4Z4Q+vyEnn3P4t0XzK/W+ODN5/kPfRLewAJVEQ0AAAAASUVORK5CYII%3D" alt="" width="24" height="24" /></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.endlesscode.com/2009/12/28/javascript-grammar/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

