<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><title>Cat in dotNET</title><link>http://www.cnblogs.com/cathsfz/</link><description /><language>zh-cn</language><lastBuildDate>Thu, 12 Nov 2009 03:28:50 GMT</lastBuildDate><pubDate>Thu, 12 Nov 2009 03:28:50 GMT</pubDate><ttl>60</ttl><geo:lat>23.1</geo:lat><geo:long>113.2</geo:long><image><link>http://claimID.com/Cat</link><url>http://static.flickr.com/95/buddyicons/45201686@N00.jpg?1161510808</url><title>Cat Chen</title></image><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/CatChen/dotNET" type="application/rss+xml" /><feedburner:emailServiceId>CatChen/dotNET</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item><title>我在 TechEd 2009 演讲的资源 (Silverlight &amp;amp; Ajax)</title><link>http://feedproxy.google.com/~r/CatChen/dotNET/~3/cdk8K1Qo0GE/1599674.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Tue, 10 Nov 2009 03:49:00 GMT</pubDate><guid isPermaLink="false">http://www.cnblogs.com/cathsfz/archive/2009/11/10/1599674.html</guid><description>&lt;p&gt;　　阅读: 1717 评论: 8 作者: &lt;a href="http://www.cnblogs.com/cathsfz/" target="_blank"&gt;Cat Chen&lt;/a&gt; 发表于 2009-11-10 11:49 &lt;a href="http://www.cnblogs.com/cathsfz/archive/2009/11/10/1599674.html" target="_blank"&gt;原文链接&lt;/a&gt;&lt;/p&gt;&lt;p&gt;这是TechEd第二天下午的Silverlight课程资源。关于百度Hi的Silverlight实现方面的任何问题，都欢迎与我讨论。&lt;/p&gt;
&lt;div style="width: 425px; text-align: left;" id="__ss_2455600"&gt;&lt;a target="_blank" style="margin: 12px 0pt 3px; font-family: Helvetica,Arial,Sans-serif; font-style: normal; font-variant: normal; font-weight: normal; font-size: 14px; line-height: normal; font-size-adjust: none; font-stretch: normal; display: block; text-decoration: underline;" href="http://www.slideshare.net/CatChen/silverlight-ria" title="基于Silverlight的RIA架构及百度应用"&gt;基于Silverlight的RIA架构及百度应用&lt;/a&gt;&lt;object style="margin:0px" width="425" height="355"&gt;
&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=silverlightriahiv2-091109042726-phpapp01&amp;stripped_title=silverlight-ria" /&gt;
&lt;param name="allowFullScreen" value="true"/&gt;
&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=silverlightriahiv2-091109042726-phpapp01&amp;stripped_title=silverlight-ria" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;
&lt;div style="font-size: 11px; font-family: tahoma,arial; height: 26px; padding-top: 2px;"&gt;View more &lt;a target="_blank" style="text-decoration: underline;" href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a target="_blank" style="text-decoration: underline;" href="http://www.slideshare.net/CatChen"&gt;Cat Chen&lt;/a&gt;.&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;这是TechEd第三天下午ASP.NET 4课程资源。与ASP.NET AJAX 4.0相关的问题可以在此讨论。&lt;/p&gt;
&lt;div style="width:425px;text-align:left" id="__ss_2463058"&gt;&lt;a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/CatChen/aspnet-4-2463058" title="建站大业，实战ASP.NET 4"&gt;建站大业，实战ASP.NET 4&lt;/a&gt;&lt;object style="margin:0px" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=dev241-091109224923-phpapp01&amp;stripped_title=aspnet-4-2463058" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=dev241-091109224923-phpapp01&amp;stripped_title=aspnet-4-2463058" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;"&gt;View more &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/CatChen"&gt;Cat Chen&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;
&lt;img src="http://www.cnblogs.com/cathsfz/aggbug/1599674.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;　　&lt;a href="http://www.cnblogs.com/cathsfz/archive/2009/11/10/1599674.html#commentform" target="_blank"&gt;发表评论&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;新闻频道：&lt;a href="http://news.cnblogs.com/n/51095/" target="_blank"&gt;任天堂：简单制胜的逻辑&lt;/a&gt;&lt;/p&gt;&lt;p&gt;推荐链接：&lt;a href="http://kb.cnblogs.com/zt/windows7/" target="_blank"&gt;Windows 7专题发布&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;网站导航：&lt;a href="http://www.cnblogs.com" target="_blank"&gt;博客园首页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://home.cnblogs.com/" target="_blank"&gt;个人主页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://news.cnblogs.com" target="_blank"&gt;新闻&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://space.cnblogs.com" target="_blank"&gt;社区&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://space.cnblogs.com/q/" target="_blank"&gt;博问&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://home.cnblogs.com/ing/" target="_blank"&gt;闪存&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://kb.cnblogs.com" target="_blank"&gt;知识库&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/BWqukQgghEGkvx-OGcLqOssVJtE/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/BWqukQgghEGkvx-OGcLqOssVJtE/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/BWqukQgghEGkvx-OGcLqOssVJtE/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/BWqukQgghEGkvx-OGcLqOssVJtE/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=cdk8K1Qo0GE:doDV-w200vM:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=cdk8K1Qo0GE:doDV-w200vM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?i=cdk8K1Qo0GE:doDV-w200vM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=cdk8K1Qo0GE:doDV-w200vM:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=cdk8K1Qo0GE:doDV-w200vM:V-t1I-SPZMU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=V-t1I-SPZMU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=cdk8K1Qo0GE:doDV-w200vM:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CatChen/dotNET/~4/cdk8K1Qo0GE" height="1" width="1"/&gt;</description><feedburner:origLink>http://www.cnblogs.com/cathsfz/archive/2009/11/10/1599674.html</feedburner:origLink></item><item><title>SD2C 2009 (Part 2 - Session &amp;amp; Forum)</title><link>http://feedproxy.google.com/~r/CatChen/dotNET/~3/u0P74wlh1v4/1589558.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Sun, 25 Oct 2009 11:51:00 GMT</pubDate><guid isPermaLink="false">http://www.cnblogs.com/cathsfz/archive/2009/10/25/1589558.html</guid><description>&lt;p&gt;　　阅读: 1326 评论: 0 作者: &lt;a href="http://www.cnblogs.com/cathsfz/" target="_blank"&gt;Cat Chen&lt;/a&gt; 发表于 2009-10-25 19:51 &lt;a href="http://www.cnblogs.com/cathsfz/archive/2009/10/25/1589558.html" target="_blank"&gt;原文链接&lt;/a&gt;&lt;/p&gt;&lt;p&gt;SD2C的第一天晚上，我在「开放平台」和「PPT制作秘诀」两者之间犹豫，最后选择了去听蔡学镛的「尼古丁+咖啡因...不瞌睡的PPT制作秘诀」，原因是我觉得如果蔡学镛能教别人写不瞌睡PPT，那么他自己的PPT至少也应该是不瞌睡的。事后证明我的选择是没错的&amp;#8212;&amp;#8212;别人告诉我「开放平台」论坛成了平台和开发人员互相责骂对方的战场。&lt;/p&gt;&lt;p&gt;蔡学镛把制作PPT比喻为制作生鱼片，要经过选材、处理、装饰这三步。在选材方面，一个PPT讲的内容最好是相当于一章书的内容，时间不能超过90分钟，而讲述的事情不能超过7件。接下来的处理，要注意做好破题，引起受众的兴趣，并且每一小节的结束时都要有总结。一页PPT所表达的意思，有可能相当于一个词、一句话、一段话，我们应该多用表达一句话的PPT页面。最后的装饰会需要用到不少图片，通过使用正确的关键字联想策略，往往都能搜索到你想要的图片。&lt;/p&gt;&lt;p&gt;SD2C的第二天，我原计划要听听周爱民的「实践者思想」和蔡学镛的「DSL设计与实践」的，结果上午听完Gary Bennett的「iPhone SDK简介」之后就被吸引住了，下午的时间都放在iPhone相关课程上了。这说明了，课程的首要条件还是要能把人吸引住，不会让人想要睡觉，也不会让人想要换个课室看看。在满足这个前提条件后，才有资格来讨论内容的知识性如何。我在听了几节iPhone开发的课程后，又开始对iPhone开发充满兴趣了。&lt;/p&gt;&lt;p&gt;晚上的「程序员软技能」论坛是我最期待的，因为这个话题可以讲得非常有震撼性。讲得好的话，这可以让很多程序员发现自身的unknown unknown（不知道自己不知道的事情）来，把这变为known unknown（知道自己不知道的事情）之后，只要努力了就能获得改善。结果主持人刘江自己戴上了嘉宾的帽子就开始不停地说，搞到台下有人举手说「在刚才的30分钟里面您已经讲了20分钟喇」。同时，估计因为刘江是做图书的，所以花了不少时间在读书的话题上，此外再提到了一些企业文化和沟通技能之类的东西，顺便还鄙视了一轮内地的高等教育连幼儿教育都不如（来自台湾清华的蔡学镛很无辜地无法参与到这个话题中来）。可能是我原本对这个话题的期望太高，所以我对这个论坛挺失望的。将来有空我会专门写文章讨论一下程序员常见的unknown unknown。&lt;/p&gt;&lt;p&gt;最后一天的SD2C我没有参加，因为已经没什么让我想要听的了，所以我选择了去参加Windows 7 Community Launch。有微软社区的人说SD2C是「傻蛋2.0大会」，选择了Visual Studio 2010 Beta 2 Launch、Windows 7 Launch、Windows 7 Community Launch这三天来举行，分明就是跟微软过不去。说实在的，我也觉得今年的SD2C日期选择失策了，明知道Windows 7对Microsoft有多么重要，也明知道发布日期是哪一天，还偏要选择一个冲突的日期。希望明年的SD2C能够选择一个更好的时间吧，相信会务今年已经通过举手投票搞清楚大家的喜好了&amp;#8212;&amp;#8212;最好是在星期二三四开会，因为星期一和星期五工作压力小，同时星期六日是用来休息的。
&lt;img src="http://www.cnblogs.com/cathsfz/aggbug/1589558.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;　　&lt;a href="http://www.cnblogs.com/cathsfz/archive/2009/10/25/1589558.html#commentform" target="_blank"&gt;发表评论&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;新闻频道：&lt;a href="http://news.cnblogs.com/n/51093/" target="_blank"&gt;微软明年2月提前推电容触摸屏WM手机&lt;/a&gt;&lt;/p&gt;&lt;p&gt;推荐链接：&lt;a href="http://kb.cnblogs.com/zt/windows7/" target="_blank"&gt;Windows 7专题发布&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;网站导航：&lt;a href="http://www.cnblogs.com" target="_blank"&gt;博客园首页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://home.cnblogs.com/" target="_blank"&gt;个人主页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://news.cnblogs.com" target="_blank"&gt;新闻&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://space.cnblogs.com" target="_blank"&gt;社区&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://space.cnblogs.com/q/" target="_blank"&gt;博问&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://home.cnblogs.com/ing/" target="_blank"&gt;闪存&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://kb.cnblogs.com" target="_blank"&gt;知识库&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/z9ofsZc5PyE9hkUSzPSRoBXPQ10/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/z9ofsZc5PyE9hkUSzPSRoBXPQ10/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/z9ofsZc5PyE9hkUSzPSRoBXPQ10/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/z9ofsZc5PyE9hkUSzPSRoBXPQ10/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=u0P74wlh1v4:54TMy0MLHf8:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=u0P74wlh1v4:54TMy0MLHf8:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?i=u0P74wlh1v4:54TMy0MLHf8:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=u0P74wlh1v4:54TMy0MLHf8:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=u0P74wlh1v4:54TMy0MLHf8:V-t1I-SPZMU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=V-t1I-SPZMU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=u0P74wlh1v4:54TMy0MLHf8:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CatChen/dotNET/~4/u0P74wlh1v4" height="1" width="1"/&gt;</description><feedburner:origLink>http://www.cnblogs.com/cathsfz/archive/2009/10/25/1589558.html</feedburner:origLink></item><item><title>SD2C 2009 (Part 1 - Keynote &amp;amp; Meal)</title><link>http://feedproxy.google.com/~r/CatChen/dotNET/~3/daet7EVdcJE/1588389.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Thu, 22 Oct 2009 16:13:00 GMT</pubDate><guid isPermaLink="false">http://www.cnblogs.com/cathsfz/archive/2009/10/23/1588389.html</guid><description>&lt;p&gt;　　阅读: 1666 评论: 5 作者: &lt;a href="http://www.cnblogs.com/cathsfz/" target="_blank"&gt;Cat Chen&lt;/a&gt; 发表于 2009-10-23 00:13 &lt;a href="http://www.cnblogs.com/cathsfz/archive/2009/10/23/1588389.html" target="_blank"&gt;原文链接&lt;/a&gt;&lt;/p&gt;&lt;p&gt;一年一度的SD2C又来了，今年的时间由去年的两天半扩充到三天，第一天只设主会场，全部都是keynote。&lt;/p&gt;&lt;p&gt;跟去年的情况类似的是，keynote环节基本上就是赞助商专场，每个赞助商都来从技术的角度说一下自己当前最重视的市场。例如说Microsoft开始重视Team Foundation Server的市场占有率了，于是就在Visual Studio 2010的keynote上介绍TFS的特性，所占比例比VS2010自身还要多。当然，keynote里面也有一些是有启发性的，例如IBM讲的大型企业中的敏捷实践，这就属于我认为比较好的keynote。&lt;/p&gt;&lt;p&gt;由于今年的话题集中在云和移动上面，所以keynote大多与这两个领域相关。能够上去讲keynote的人，当然是要有一定水平的，不能讲一些很肤浅的内容，但如果因此就把keynote弄得很高深或者很抽象又弄巧成拙了。高深的内容固然能够表现出演讲者很有水平，问题是这样一个面向上千受众的活动，有多少人能够对如此多个keynote的话题都有深入了解呢？就算你对其中一个话题很有了解，觉得讲得如此有高度很对你胃口，但你也总有n个其它不了解的话题吧，那些话题你听起来也会觉得是云里雾里的。&lt;/p&gt;&lt;p&gt;在我看来，优秀的keynote应该是这样子的&amp;#8212;&amp;#8212;它能够阐述一个很新颖的观点，或者提供一种全新的视觉，使得无论你原本对这个话题了解多少，你都会被震撼到&amp;#8212;&amp;#8212;这个事情我有所了解，但为什么我之前就没有尝试过从这个角度来思考呢？这其实也就是Punch Party的优势，无论受众具备怎么样的背景，都能感受到全新观点带来的冲击力。如果能够打到这样的效果，我并不在意一个keynote是否顺便在推销某个企业或者产品。&lt;/p&gt;&lt;p&gt;接下来要说说吃饭的问题，但在此之前让我先说说我对MVP Program的一些观点，这纯粹是个人观点，也不一定符合事实。我觉得，就拿MVP Summit这样一个全球峰会来说，每年要接待来自全球各地的几千人，为他们提供四天的食宿，平均分摊到每个与会者身上的费用肯定是不少的。如果MVP Summit的作用仅仅在于让大家聊聊技术，我想Microsoft作为一家商业公司是不会愿意花这笔钱的，就算Microsoft想要这样做，股东们也不会同意。因此，MVP Program必然是能够产生价值的，并且分摊下来每位MVP为Microsoft创造的价值应该大于Microsoft为他所作的花费。这些价值可能包括，MVP为用户解答问题，为客户带来技术培训，也就相当于节省了Microsoft的服务成本和市场费用。同时，MVP也会积极反馈关于产品的各种问题，这也属于创造价值的部分。&lt;/p&gt;&lt;p&gt;回到SD2C的事情上来，CSDN其实对热心贡献的用户非常好，例如说提供SD2C赠票。但是CSDN从来都对此事保持非常低调的姿态，生怕激怒那些付钱买票的人，同时也怕更多人去找他们要赠票。我的疑问是，为什么这些对热心用户的正面激励不能好像MVP Program那样光明正大的做呢？如果一位热心用户为CSDN创造的价值能够大于SD2C门票的成本价，那送他一张赠票肯定还是赚了的。&lt;/p&gt;&lt;p&gt;为什么我要说这件事？因为今年的赠票不包括背包和晚餐。不包括背包我觉得可以理解，金融危机嘛，能够让我免费来参加SD2C我已经非常满足了，没有背包也没所谓。但是不包括晚餐就非常不人性化了&amp;#8212;&amp;#8212;这不是逼拿赠票的人不参加晚上的活动提前离场吗？况且，班车还要等晚上活动结束后才有，傍晚离开还是挺不方便的。于是我就在会场的做啥大屏幕发起讨论，问问没晚餐票的人准备如何吃晚餐&amp;#8212;&amp;#8212;我的本意只是想组织落单的赠票使用者一起吃饭，反正拿赠票的大多是CSDN活跃用户，大家也都是认识的。同时我考虑到CSDN不希望公开有赠票这件事，我一开始也刻意回避了这个话题，后来有人公开讨论了我也就跟着讨论了。&lt;/p&gt;&lt;p&gt;结果是什么呢？CSDN会务组单独给我一张晚餐票，并告诉我原因是蒋涛看到做啥大屏幕的内容了。这就让我感觉到很奇怪了，两天的晚餐票值多少钱呢？值得把事情搞到这样子吗？CSDN自己是做媒体的，应该十分清楚媒体的影响力。赠票邀请来的人，都是技术社区上最活跃的人，他们的博客都是具有相当影响力的媒体，给这些人留下这样一个负面印象，CSDN损失的是多少价值呢？这是否已经超过了两张晚餐票的价钱呢？我相信以蒋涛在CSDN这么多年来做媒体的经验，应该在这件事被搬上大屏幕讨论之前就把帐算清楚了吧。&lt;/p&gt;&lt;p&gt;最后一点，也就是这样做是否厚道。如果CSDN以媒体身份受邀参加这样一场大会，本来是希望借此机会向自己的读者传递更多更好的技术资讯的，然而却受到大会主办方不公平的对待，搞到连饭都没得吃，你们会喜欢被这样对待吗？如果你们自己也不喜欢被这样对待，那就在如此待人之前先考虑清楚。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/cathsfz/aggbug/1588389.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;　　&lt;a href="http://www.cnblogs.com/cathsfz/archive/2009/10/23/1588389.html#commentform" target="_blank"&gt;发表评论&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;新闻频道：&lt;a href="http://news.cnblogs.com/n/51092/" target="_blank"&gt;Windows 7上网本电池续航时间不敌XP&lt;/a&gt;&lt;/p&gt;&lt;p&gt;推荐链接：&lt;a href="http://kb.cnblogs.com/zt/windows7/" target="_blank"&gt;Windows 7专题发布&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;网站导航：&lt;a href="http://www.cnblogs.com" target="_blank"&gt;博客园首页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://home.cnblogs.com/" target="_blank"&gt;个人主页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://news.cnblogs.com" target="_blank"&gt;新闻&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://space.cnblogs.com" target="_blank"&gt;社区&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://space.cnblogs.com/q/" target="_blank"&gt;博问&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://home.cnblogs.com/ing/" target="_blank"&gt;闪存&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://kb.cnblogs.com" target="_blank"&gt;知识库&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Au8Hzlv8A55SPB8EEXjLUtCxUOE/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Au8Hzlv8A55SPB8EEXjLUtCxUOE/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Au8Hzlv8A55SPB8EEXjLUtCxUOE/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Au8Hzlv8A55SPB8EEXjLUtCxUOE/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=daet7EVdcJE:ZDjwABu7ydI:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=daet7EVdcJE:ZDjwABu7ydI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?i=daet7EVdcJE:ZDjwABu7ydI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=daet7EVdcJE:ZDjwABu7ydI:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=daet7EVdcJE:ZDjwABu7ydI:V-t1I-SPZMU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=V-t1I-SPZMU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=daet7EVdcJE:ZDjwABu7ydI:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CatChen/dotNET/~4/daet7EVdcJE" height="1" width="1"/&gt;</description><feedburner:origLink>http://www.cnblogs.com/cathsfz/archive/2009/10/23/1588389.html</feedburner:origLink></item><item><title>十分钟内学会：控制浏览器是否缓存网页状态</title><link>http://feedproxy.google.com/~r/CatChen/dotNET/~3/CoCWCK2OKZA/1579666.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Fri, 09 Oct 2009 06:59:00 GMT</pubDate><guid isPermaLink="false">http://www.cnblogs.com/cathsfz/archive/2009/10/09/1579666.html</guid><description>&lt;p&gt;　　阅读: 3466 评论: 9 作者: &lt;a href="http://www.cnblogs.com/cathsfz/" target="_blank"&gt;Cat Chen&lt;/a&gt; 发表于 2009-10-09 14:59 &lt;a href="http://www.cnblogs.com/cathsfz/archive/2009/10/09/1579666.html" target="_blank"&gt;原文链接&lt;/a&gt;&lt;/p&gt;&lt;h4&gt;Question&lt;/h4&gt;
&lt;p&gt;在Firefox等浏览器中，如果你打开一个页面并进行若干操作，例如在文本框进行输入，甚至点击按钮进行Ajax操作更新页面局部，这些操作的结果都会被缓存下来。在你点击链接离开这个页面后，如果你通过后退按钮回到这个页面，你会发现它仍出于你离开时的状态，而非页面刚刚加载好后的初始状态。在一些情况下，这样的缓存方式是符合我们预期的；但在另外一些情况下，我们更希望页面恢复到初始状态，或者说让页面从零开始重新加载一边。我们如何才能让浏览器尊重我们的选择呢？&lt;/p&gt;
&lt;p&gt;
&lt;/p&gt;
&lt;h4&gt;Answer&lt;/h4&gt;
&lt;p&gt;如果你只是希望页面不缓存加载后的变更，后退就恢复到最初加载的状态，你只需要一个空白的unload事件就可以了：&lt;/p&gt;
&lt;code&gt;window.onunload = function(){};&lt;/code&gt;
&lt;p&gt;其中的原理是，Firefox等浏览器会尝试通过&amp;#8220;挂起（suspend）&amp;#8221;的方式来缓存页面，使得后退能够恢复到页面之前被挂起那一刻的状态。然而如果unload事件有处理函数，浏览器就认为你可能已经对页面进行了析构处理，这时候页面已经不可能回到正常的交互状态，也就不能以挂起的方式来缓存页面。&lt;/p&gt;
&lt;p&gt;如果我们希望允许浏览器挂起页面，同时又需要知道何时被挂起何时被恢复，那该怎么办呢？我们可以用window对象上的pageshow和pagehide事件。当页面被挂起并隐藏时，pagehide事件会被触发；当页面被恢复到挂起前状态并显示出来时，pageshow事件会被触发。&lt;a href="https://developer.mozilla.org/en/Using_Firefox_1.5_caching"&gt;Firefox&lt;/a&gt;从1.5开始就支持这两个事件，&lt;a href="http://webkit.org/blog/516/webkit-page-cache-ii-the-unload-event/"&gt;Safari&lt;/a&gt;最新的nightly build也支持这两个事件。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/cathsfz/aggbug/1579666.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;　　&lt;a href="http://www.cnblogs.com/cathsfz/archive/2009/10/09/1579666.html#commentform" target="_blank"&gt;发表评论&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;新闻频道：&lt;a href="http://news.cnblogs.com/n/51091/" target="_blank"&gt;苹果发布Safari 4.0.4 完善JavaScript性能&lt;/a&gt;&lt;/p&gt;&lt;p&gt;推荐链接：&lt;a href="http://kb.cnblogs.com/zt/windows7/" target="_blank"&gt;Windows 7专题发布&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;网站导航：&lt;a href="http://www.cnblogs.com" target="_blank"&gt;博客园首页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://home.cnblogs.com/" target="_blank"&gt;个人主页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://news.cnblogs.com" target="_blank"&gt;新闻&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://space.cnblogs.com" target="_blank"&gt;社区&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://space.cnblogs.com/q/" target="_blank"&gt;博问&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://home.cnblogs.com/ing/" target="_blank"&gt;闪存&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://kb.cnblogs.com" target="_blank"&gt;知识库&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/VDS9g3rwOesloQZ-DCLp5bjwGRA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/VDS9g3rwOesloQZ-DCLp5bjwGRA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/VDS9g3rwOesloQZ-DCLp5bjwGRA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/VDS9g3rwOesloQZ-DCLp5bjwGRA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=CoCWCK2OKZA:_5a7PS4K4NQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=CoCWCK2OKZA:_5a7PS4K4NQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?i=CoCWCK2OKZA:_5a7PS4K4NQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=CoCWCK2OKZA:_5a7PS4K4NQ:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=CoCWCK2OKZA:_5a7PS4K4NQ:V-t1I-SPZMU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=V-t1I-SPZMU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=CoCWCK2OKZA:_5a7PS4K4NQ:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CatChen/dotNET/~4/CoCWCK2OKZA" height="1" width="1"/&gt;</description><feedburner:origLink>http://www.cnblogs.com/cathsfz/archive/2009/10/09/1579666.html</feedburner:origLink></item><item><title>你的网站「被兼容」了吗？</title><link>http://feedproxy.google.com/~r/CatChen/dotNET/~3/T1nm1oCa7H4/1568549.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Thu, 17 Sep 2009 07:35:00 GMT</pubDate><guid isPermaLink="false">http://www.cnblogs.com/cathsfz/archive/2009/09/17/1568549.html</guid><description>&lt;p&gt;　　阅读: 3192 评论: 26 作者: &lt;a href="http://www.cnblogs.com/cathsfz/" target="_blank"&gt;Cat Chen&lt;/a&gt; 发表于 2009-09-17 15:35 &lt;a href="http://www.cnblogs.com/cathsfz/archive/2009/09/17/1568549.html" target="_blank"&gt;原文链接&lt;/a&gt;&lt;/p&gt;&lt;p&gt;一般情况下，我们只会讨论我们的网站如何主动兼容某某浏览器，被动地等待浏览器来兼容我们的网站是不切实际的幻想&amp;#8212;&amp;#8212;哪个浏览器会那么伟大，原意主动为一个不兼容的网站而作出改变呢？IE8就是这样一个伟大的浏览器，Microsoft就是一家这样伟大的企业。&lt;/p&gt;
&lt;p&gt;故事是这样的，我们有一小段JavaScript依赖于userAgent属性，同样是用IE8进行浏览，在测试环境上userAgent显示为MSIE 7.0，而在生产环境上userAgent显示为MSIE 8.0。为什么会这样呢？打开Developer Toolbar后，发现原来是Browser Mode这个开关在搞鬼&amp;#8212;&amp;#8212;当Browser Mode是Internet Explorer 8的时候，userAgent就是MSIE 8.0；当Browser Mode是Internet Explorer 8 Compatibility View（兼容性视图）或Internet Explorer 7的时候，userAgent就是MSIE 7.0了。&lt;/p&gt;
&lt;p&gt;接下来的问题是，我们并没有刻意去拨动这个开关啊，两个相同的页面怎么在不同的环境中默认显示为不同的Browser Mode呢？我的猜想是，这是由于域名不同而引起的&amp;#8212;&amp;#8212;Microsoft自己维护着一个&lt;a href="http://msdn.microsoft.com/en-us/library/dd567845%28VS.85%29.aspx"&gt;Compatibility View List&lt;/a&gt;，当访问该List中的站点时，IE8会自动启用Compatibility View，也就是将Browser Mode切换到Internet Explorer 8 Compatibility View。接着我在地址栏输入以下地址，检查了一下我本地最近更新的List：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;res://iecompat.dll/iecompatdata.xml&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;事实表明，我们测试用的baidu.com域名确实在上述List中，但部署到baidu.jp后也就脱离了该List。这就很好地解释了我们遇到问题，同时也提醒我们域名已经成为了IE8测试中不可避免的一个紧耦合因素。在过去，我们可以简单地认为，部署在不同URL的相同页面在同一款浏览器中显示出来总是一样的。但现在我们必须修正这句话了，仅当不同URL都基于同一个域名时上述命题仍然成立。&lt;/p&gt;
&lt;p&gt;通过这个案例，希望能让大家了解到在开发与测试过程中保持域名一致的重要性。如果你开发的页面要部署到example.com，你最好在develop.example.com上开发，在test.example.com上测试，然后再部署。如果你需要在本机进行开发测试，也要通过改hosts模拟一个localhost.example.com来进行测试与调试，以确保代码在最终部署后能执行在相同的环境下。&lt;/p&gt;&lt;img src="http://www.cnblogs.com/cathsfz/aggbug/1568549.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;　　&lt;a href="http://www.cnblogs.com/cathsfz/archive/2009/09/17/1568549.html#commentform" target="_blank"&gt;发表评论&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;新闻频道：&lt;a href="http://news.cnblogs.com/n/51090/" target="_blank"&gt;微软为Bing搜索引擎增加更多获取信息的功能&lt;/a&gt;&lt;/p&gt;&lt;p&gt;推荐链接：&lt;a href="http://kb.cnblogs.com/zt/windows7/" target="_blank"&gt;Windows 7专题发布&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;网站导航：&lt;a href="http://www.cnblogs.com" target="_blank"&gt;博客园首页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://home.cnblogs.com/" target="_blank"&gt;个人主页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://news.cnblogs.com" target="_blank"&gt;新闻&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://space.cnblogs.com" target="_blank"&gt;社区&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://space.cnblogs.com/q/" target="_blank"&gt;博问&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://home.cnblogs.com/ing/" target="_blank"&gt;闪存&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://kb.cnblogs.com" target="_blank"&gt;知识库&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/Q0ijbUNh7JP_iNXWOh9WMw3yb18/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Q0ijbUNh7JP_iNXWOh9WMw3yb18/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/Q0ijbUNh7JP_iNXWOh9WMw3yb18/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/Q0ijbUNh7JP_iNXWOh9WMw3yb18/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=T1nm1oCa7H4:UHVKfq6O3Wc:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=T1nm1oCa7H4:UHVKfq6O3Wc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?i=T1nm1oCa7H4:UHVKfq6O3Wc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=T1nm1oCa7H4:UHVKfq6O3Wc:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=T1nm1oCa7H4:UHVKfq6O3Wc:V-t1I-SPZMU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=V-t1I-SPZMU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=T1nm1oCa7H4:UHVKfq6O3Wc:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CatChen/dotNET/~4/T1nm1oCa7H4" height="1" width="1"/&gt;</description><feedburner:origLink>http://www.cnblogs.com/cathsfz/archive/2009/09/17/1568549.html</feedburner:origLink></item><item><title>jQuery is DSL (Part 2 - jQuery)</title><link>http://feedproxy.google.com/~r/CatChen/dotNET/~3/ArBky5zgjy8/1547361.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Sun, 16 Aug 2009 16:01:00 GMT</pubDate><guid isPermaLink="false">http://www.cnblogs.com/cathsfz/archive/2009/08/17/1547361.html</guid><description>&lt;p&gt;　　阅读: 2532 评论: 3 作者: &lt;a href="http://www.cnblogs.com/cathsfz/" target="_blank"&gt;Cat Chen&lt;/a&gt; 发表于 2009-08-17 00:01 &lt;a href="http://www.cnblogs.com/cathsfz/archive/2009/08/17/1547361.html" target="_blank"&gt;原文链接&lt;/a&gt;&lt;/p&gt;&lt;h4&gt;jQuery的Internal DSL形式&lt;/h4&gt;
&lt;p&gt;在上一篇文章里面，我们了解到了Internal DSL的具体形式，形如：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/* Method Chaining */&lt;br /&gt;
computer()&lt;br /&gt;
&amp;nbsp; .processor()&lt;br /&gt;
&amp;nbsp; &amp;nbsp; .cores(2)&lt;br /&gt;
&amp;nbsp; &amp;nbsp; .i386()&lt;br /&gt;
&amp;nbsp; .disk()&lt;br /&gt;
&amp;nbsp; &amp;nbsp; .size(150)&lt;br /&gt;
&amp;nbsp; .disk()&lt;br /&gt;
&amp;nbsp; &amp;nbsp; .size(75)&lt;br /&gt;
&amp;nbsp; &amp;nbsp; .speed(7200)&lt;br /&gt;
&amp;nbsp; &amp;nbsp; .sata()&lt;br /&gt;
&amp;nbsp; .end();&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;然后我们在看看一段典型的jQuery代码：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$("ul#contacts li.item")&lt;br /&gt;
&amp;nbsp; .find("span.name")&lt;br /&gt;
&amp;nbsp; &amp;nbsp; .click(function(e) { $(e.target).siblings(".more").toggle(); })&lt;br /&gt;
&amp;nbsp; &amp;nbsp; .end()&lt;br /&gt;
&amp;nbsp; .find("input.delete")&lt;br /&gt;
&amp;nbsp; &amp;nbsp; .click(function(e) { $(e.target).parents(".item").remove(); })&lt;br /&gt;
&amp;nbsp; &amp;nbsp; .end()&lt;br /&gt;
&amp;nbsp; .find("div.more")&lt;br /&gt;
&amp;nbsp; &amp;nbsp; .hide()&lt;br /&gt;
&amp;nbsp; &amp;nbsp; .end();&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;从结构上来说，是不是跟上面那一段Internal DSL的例子很相似？就算我们不看对应的HTML，我们也能猜到这段jQuery代码的含义：&lt;/p&gt;
&lt;ul&gt;
     &lt;li&gt;遍历&lt;code&gt;&amp;lt;ul id="contacts"&amp;gt;&lt;/code&gt;中的每一个&lt;code&gt;&amp;lt;li class="item"&amp;gt;&lt;/code&gt;&lt;br /&gt;
     （这看起来是个联系人列表）
     &lt;ul&gt;
         &lt;li&gt;对于里面的&lt;code&gt;&amp;lt;span class="name"&amp;gt;&lt;/code&gt;
         &lt;ul&gt;
             &lt;li&gt;绑定&lt;code&gt;click&lt;/code&gt;事件，操作是显示/隐藏&lt;code&gt;class="more"&lt;/code&gt;兄弟节点&lt;br /&gt;
             （这是估计联系人姓名，点击后切换详细信息的显示/隐藏）&lt;/li&gt;
         &lt;/ul&gt;
         &lt;/li&gt;
         &lt;li&gt;对于里面的&lt;code&gt;&amp;lt;input class="delete"&amp;gt;&lt;/code&gt;
         &lt;ul&gt;
             &lt;li&gt;绑定&lt;code&gt;click&lt;/code&gt;事件，操作是把&lt;code&gt;class="item"&lt;/code&gt;父节点删除&lt;br /&gt;
             （这应该是用来删除联系人的）&lt;/li&gt;
         &lt;/ul&gt;
         &lt;/li&gt;
         &lt;li&gt;对于里面的&lt;code&gt;&amp;lt;div class="more"&amp;gt;&lt;/code&gt;
         &lt;ul&gt;
             &lt;li&gt;隐藏这个&lt;code&gt;div&lt;/code&gt;&lt;br /&gt;
             （默认隐藏详细信息？）&lt;/li&gt;
         &lt;/ul&gt;
         &lt;/li&gt;
     &lt;/ul&gt;
     &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;从这里我们已经能够看出jQuery的Internal DSL形式带来的好处&amp;#8212;&amp;#8212;编写代码时，让代码更贴近作者的思维模式；阅读代码时，让读者更容易理解代码的含义。不信？我们看看与jQuery拥有相似功能的Prototype是如何实现上述逻辑：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;$$("ul#contacts li.item span.name")&lt;br /&gt;
&amp;nbsp; .invoke("observe", "click",&lt;br /&gt;
&amp;nbsp; &amp;nbsp; function(e) { $(e.target).next(".more").toggle(); });&lt;br /&gt;
$$("ul#contacts li.item input.delete")&lt;br /&gt;
&amp;nbsp; .invoke("observe", "click",&lt;br /&gt;
&amp;nbsp; &amp;nbsp; function(e) { $(e.target).up(".item").remove(); });&lt;br /&gt;
$$("ul#contacts li.item div.more")&lt;br /&gt;
&amp;nbsp; .invoke("hide");&lt;br /&gt;
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;这是我用Prototype所能写出的最贴近Internal DSL的形式了。（如果你能够写出一个更自然的版本，欢迎分享。）在Prototype里面，能够返回一组元素的操作就只有&lt;code&gt;$$()&lt;/code&gt;，并且它只能作用于全局，缺乏jQuery中&lt;code&gt;find()&lt;/code&gt;或者&lt;code&gt;filter()&lt;/code&gt;的功能，所以这一组描述联系人列表行为的语句无法组合在一起，必须逐一定义每类元素的行为。此外，此例子中每类元素都仅仅指定了一个行为，因此Prototype的&lt;code&gt;invoke()&lt;/code&gt;写法看起来还是和jQuery的&lt;code&gt;click()&lt;/code&gt;写法很相近的。但如果一类元素拥有多个行为，Prototype的&lt;code&gt;invoke()&lt;/code&gt;就不能好像jQuery那样链式调用下去了，必须每一个行为重头写一个&lt;code&gt;$$()&lt;/code&gt;，或者把&lt;code&gt;invoke()&lt;/code&gt;改成&lt;code&gt;each()&lt;/code&gt;加匿名函数。无论是那种做法，都只会降低代码的可读性。&lt;/p&gt;
&lt;h4&gt;jQuery的语法分析器&lt;/h4&gt;
我们都知道，Internal DSL的实现依赖于对语法分析器的封装，对Internal DSL的调用其实都是对语法分析器的调用，经过语法分析后再构造出对底层API的调用。例如jQuery当中的&lt;code&gt;click()&lt;/code&gt;，它依赖于当前的状态，也就是前面&lt;code&gt;$()&lt;/code&gt;筛选出来的节点集合，把&lt;code&gt;click()&lt;/code&gt;解释为要为这一组节点绑定DOM的click事件，最后再调用DOM API完成任务。在这个例子当中，DOM API相对jQuery API而言就是底层API了。&lt;/p&gt;
&lt;p&gt;jQuery可以说是挑了一个最容易实现的语法模型来做，永远只有一种token，因此永远也只有一种状态，这种状态当然也是永远有效的，你根本不可能给jQuery输入一个当前状态无效的token。jQuery的唯一状态就是一个jQuery对象实例，其本质就是一个元素集合。读入的token可能是各种针对这个元素集合的操作，但它的返回一定还是一个元素集合。这使得jQuery的语法分析器不会进入无效状态，也就无需判断无效状态，因此大大简化了Internal DSL实现中常见的一个难题。&lt;/p&gt;
&lt;h4&gt;小结&lt;/h4&gt;
&lt;p&gt;通过拿jQuery和Prototype做对比，我们可以发现jQuery用非常低的成本实现了Internal DSL，同时带来了Prototype所没有的明显好处。这可以看作是一个很好的范例&amp;#8212;&amp;#8212;如果你需要描述的业务逻辑能够归纳为简单的语言模式，为此实现一门Internal DSL的性价比将会是很高的。你需要做的仅仅是为这个简单的语言模型实现一个简单的解释器，接着你就可以享受贴近人类思维模式的接口了。&lt;/p&gt;
&lt;p&gt;最后，如果你喜欢我的文章，可以考虑订阅我的博客：&lt;/p&gt;
&lt;ul&gt;
     &lt;li&gt;&lt;a href="http://chinese.catchen.biz/"&gt;Cat in
     Chinese&lt;/a&gt; (&lt;a href="http://feedproxy.google.com/CatChen/Chinese"&gt;feed&lt;/a&gt;)&lt;/li&gt;
     &lt;li&gt;&lt;a href="http://dotnet.catchen.biz/"&gt;Cat in dotNET&lt;/a&gt; (&lt;a href="http://feedproxy.google.com/CatChen/dotNET"&gt;feed&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;img src="http://www.cnblogs.com/cathsfz/aggbug/1547361.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;　　&lt;a href="http://www.cnblogs.com/cathsfz/archive/2009/08/17/1547361.html#commentform" target="_blank"&gt;发表评论&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;新闻频道：&lt;a href="http://news.cnblogs.com/n/51089/" target="_blank"&gt;迄今为止苹果推出的12款最烂产品&lt;/a&gt;&lt;/p&gt;&lt;p&gt;推荐链接：&lt;a href="http://kb.cnblogs.com/zt/windows7/" target="_blank"&gt;Windows 7专题发布&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;网站导航：&lt;a href="http://www.cnblogs.com" target="_blank"&gt;博客园首页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://home.cnblogs.com/" target="_blank"&gt;个人主页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://news.cnblogs.com" target="_blank"&gt;新闻&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://space.cnblogs.com" target="_blank"&gt;社区&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://space.cnblogs.com/q/" target="_blank"&gt;博问&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://home.cnblogs.com/ing/" target="_blank"&gt;闪存&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://kb.cnblogs.com" target="_blank"&gt;知识库&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/oi6H909Ya4UsdTcVoJqUeY3jpvk/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/oi6H909Ya4UsdTcVoJqUeY3jpvk/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/oi6H909Ya4UsdTcVoJqUeY3jpvk/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/oi6H909Ya4UsdTcVoJqUeY3jpvk/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=ArBky5zgjy8:j6MP2zp98bQ:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=ArBky5zgjy8:j6MP2zp98bQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?i=ArBky5zgjy8:j6MP2zp98bQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=ArBky5zgjy8:j6MP2zp98bQ:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=ArBky5zgjy8:j6MP2zp98bQ:V-t1I-SPZMU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=V-t1I-SPZMU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=ArBky5zgjy8:j6MP2zp98bQ:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CatChen/dotNET/~4/ArBky5zgjy8" height="1" width="1"/&gt;</description><feedburner:origLink>http://www.cnblogs.com/cathsfz/archive/2009/08/17/1547361.html</feedburner:origLink></item><item><title>jQuery is DSL (Part 1 - DSL)</title><link>http://feedproxy.google.com/~r/CatChen/dotNET/~3/zfQLo0sX71c/1543266.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Mon, 10 Aug 2009 15:47:00 GMT</pubDate><guid isPermaLink="false">http://www.cnblogs.com/cathsfz/archive/2009/08/10/1543266.html</guid><description>&lt;p&gt;　　阅读: 3932 评论: 29 作者: &lt;a href="http://www.cnblogs.com/cathsfz/" target="_blank"&gt;Cat Chen&lt;/a&gt; 发表于 2009-08-10 23:47 &lt;a href="http://www.cnblogs.com/cathsfz/archive/2009/08/10/1543266.html" target="_blank"&gt;原文链接&lt;/a&gt;&lt;/p&gt;&lt;p&gt;jQuery刚刚出来的时候，我没有太多关注它，觉得这不过是Yet Another JavaScript Library。早期的jQuery专注于DOM节点的筛选与操作，不提供众多的基础类扩展，更不提供UI组件，因此体积能够做到很小。然而，我实在看不出它和我熟悉的Prototype比有什么明显的优势&amp;#8212;&amp;#8212;jQuery能做的各项独立的操作，Prototype都能做。&lt;/p&gt;
&lt;p&gt;后来用jQuery的人越来越多，并且大家都爱用它的链式方法调用，甚至还把这种写法推广到其它语言中去。例如ASP.NET MVP &lt;a href="http://msmvps.com/blogs/omar/default.aspx"&gt;Omar AL Zabir&lt;/a&gt;就把他的服务器端C#组件设计为支持链式方法调用的。这时候我才开始关注jQuery，并且逐渐喜欢上了链式方法调用的写法，也在我自己的JavaScript组件中实现类似的API（参考&lt;a href="http://www.cnblogs.com/cathsfz/archive/2009/05/06/1450332.html"&gt;Async&lt;/a&gt;和&lt;a href="http://www.cnblogs.com/cathsfz/archive/2009/07/02/1515188.html"&gt;Overload&lt;/a&gt;）。最后，我突然明白到，这其实就是一种Internal DSL嘛！&lt;/p&gt;
&lt;p&gt;在这篇文章里，我准备先讨论Internal DSL，在下一篇文章里面再解释为什么jQuery是Internal DSL。现在我们就从最根本的问题开始吧&amp;#8212;&amp;#8212;&lt;/p&gt;
&lt;h4&gt;什么是Internal DSL？&lt;/h4&gt;
&lt;p&gt;DSL是指Domain Specific Language，也就是用于描述和解决特定领域问题的语言。例如说，我们有专门描述字符串特征的正则表达式，有专门描述数据库查询的SQL，有专门描述XML结构的DTD和XSD，甚至有专门描述XML变换的XSLT，这些都是DSL。&lt;/p&gt;
&lt;p&gt;当然，并非我们关注的领域都有现成的DSL，这时候我们有三个选择：
&lt;ol&gt;
     &lt;li&gt;使用通用语言描述该领域的问题（non-DSL）&lt;/li&gt;
     &lt;li&gt;发明一门全新的语言描述该领域的问题（&lt;a href="http://martinfowler.com/dslwip/ExternalOverview.html"&gt;External DSL&lt;/a&gt;）&lt;/li&gt;
     &lt;li&gt;在一门现成语言内实现针对领域问题的描述（&lt;a href="http://martinfowler.com/dslwip/InternalOverview.html"&gt;Internal DSL&lt;/a&gt;）&lt;/li&gt;
&lt;/ol&gt;
例如说，我们现在要描述一个很简单的金融领域问题，&amp;#8220;我在花旗银行存款$200&amp;#8221;这样一句话对应的三种法写法可能是：（假设已经存在I和CitiBank两个实体实例）
&lt;ol&gt;
     &lt;li&gt;&lt;code&gt;I.DepositTo(new USD(200), CitiBank); /* C# */&lt;/code&gt;&lt;/li&gt;
     &lt;li&gt;&lt;code&gt;I deposit 200USD to CitiBank /* E-DSL */&lt;/code&gt;&lt;/li&gt;
     &lt;li&gt;&lt;code&gt;I.deposit(200.USD()).to(CitiBank); /* I-DSL */&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
第1种做法的成本最低，你只需要有OO的思想就可以了，你总能把实体类设计出来，但可能和人类描述此领域问题的思维方式有一定偏差（为什么USD可以new？为什么不是&lt;code&gt;deposit [something] to [somewhere]&lt;/code&gt;？）。&lt;/p&gt;
&lt;p&gt;第2种做法的成本最高，你需要写一个全新的解释器，至少是写一组全新的规则，然后让YACC这类工具帮你生成一个解释器，但这样出来的语法最贴近人类思维方式，甚至就如同自然语言一样流畅。&lt;/p&gt;
&lt;p&gt;第3种做法术语上述两者的折中方案，如果语法不太复杂可以使用Builder模式实现语法分析，写出来的语法相当贴近自然语言，但还是有学习门槛。由于脚本语言有相当的灵活性，所以现在很多人倾向于选择在脚本语言内实现Internal DSL。&lt;/p&gt;
&lt;h4&gt;如何构造Internal DSL？&lt;/h4&gt;
&lt;p&gt;常见的两种Internal DSL实现方法是&lt;a href="http://martinfowler.com/dslwip/MethodChaining.html"&gt;Method Chaining&lt;/a&gt;和&lt;a href=""&gt;Function Sequence&lt;/a&gt;。如果我们需要描述一台机器的硬件组成，两种实现方式的代码分别如下：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/* Method Chaining */&lt;br /&gt;
computer()&lt;br /&gt;
&amp;nbsp; .processor()&lt;br /&gt;
&amp;nbsp; &amp;nbsp; .cores(2)&lt;br /&gt;
&amp;nbsp; &amp;nbsp; .i386()&lt;br /&gt;
&amp;nbsp; .disk()&lt;br /&gt;
&amp;nbsp; &amp;nbsp; .size(150)&lt;br /&gt;
&amp;nbsp; .disk()&lt;br /&gt;
&amp;nbsp; &amp;nbsp; .size(75)&lt;br /&gt;
&amp;nbsp; &amp;nbsp; .speed(7200)&lt;br /&gt;
&amp;nbsp; &amp;nbsp; .sata()&lt;br /&gt;
&amp;nbsp; .end();&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;/* Function Sequence */&lt;br /&gt;
computer();&lt;br /&gt;
&amp;nbsp; processor();&lt;br /&gt;
&amp;nbsp; &amp;nbsp; cores(2);&lt;br /&gt;
&amp;nbsp; &amp;nbsp; processorType(i386);&lt;br /&gt;
&amp;nbsp; disk();&lt;br /&gt;
&amp;nbsp; &amp;nbsp; diskSize(150);&lt;br /&gt;
&amp;nbsp; disk();&lt;br /&gt;
&amp;nbsp; &amp;nbsp; diskSize(75);&lt;br /&gt;
&amp;nbsp; &amp;nbsp; diskSpeed(7200);&lt;br /&gt;
&amp;nbsp; &amp;nbsp; diskInterface(SATA);&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;无论是哪一种写法，中间都必须写一个分析器层。就如同语法分析器需要使用状态机一样，Internal DSL的实现也必须内置一个状态机，以记录当前执行到什么状态了，并且接下来可以转移到哪些有效状态。&lt;/p&gt;
&lt;p&gt;由于这不是一篇专门讲语法分析器和状态机实现的文章，所以我们把关注点保持在API层面就可以了，不深入讨论其实现细节和成本。我们知道链式方法调用能够实现Internal DSL就够了，至于jQuery是如何利用好这一点的，我们在下一篇文章里再作讨论。&lt;/p&gt;
&lt;h4&gt;小结&lt;/h4&gt;
&lt;p&gt;在这篇文章里，我们了解了Internal DSL与External DSL之间的区别，同时还了解到实现Internal DSL的具体方式，这为我们接下来讨论jQuery的Internal DSL式接口做好了铺垫。在下一篇文章里，我们将深入地来看看为什么jQuery的接口要如此设计，它能为用户带来了怎样的便利，同时它自身的实现上又有什么优势。&lt;/p&gt;
&lt;p&gt;如果你不希望错过下一篇文章，你可以考虑订阅我的博客：&lt;/p&gt;
&lt;ul&gt;
     &lt;li&gt;&lt;a href="http://chinese.catchen.biz/"&gt;Cat in
     Chinese&lt;/a&gt; (&lt;a href="http://feedproxy.google.com/CatChen/Chinese"&gt;feed&lt;/a&gt;)&lt;/li&gt;
     &lt;li&gt;&lt;a href="http://dotnet.catchen.biz/"&gt;Cat in dotNET&lt;/a&gt; (&lt;a href="http://feedproxy.google.com/CatChen/dotNET"&gt;feed&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;img src="http://www.cnblogs.com/cathsfz/aggbug/1543266.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;　　&lt;a href="http://www.cnblogs.com/cathsfz/archive/2009/08/10/1543266.html#commentform" target="_blank"&gt;发表评论&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;新闻频道：&lt;a href="http://news.cnblogs.com/n/51087/" target="_blank"&gt;社交网站用户超过1亿&lt;/a&gt;&lt;/p&gt;&lt;p&gt;推荐链接：&lt;a href="http://kb.cnblogs.com/zt/windows7/" target="_blank"&gt;Windows 7专题发布&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;网站导航：&lt;a href="http://www.cnblogs.com" target="_blank"&gt;博客园首页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://home.cnblogs.com/" target="_blank"&gt;个人主页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://news.cnblogs.com" target="_blank"&gt;新闻&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://space.cnblogs.com" target="_blank"&gt;社区&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://space.cnblogs.com/q/" target="_blank"&gt;博问&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://home.cnblogs.com/ing/" target="_blank"&gt;闪存&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://kb.cnblogs.com" target="_blank"&gt;知识库&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/emTOH31sAqW3piy680Deioyis7E/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/emTOH31sAqW3piy680Deioyis7E/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/emTOH31sAqW3piy680Deioyis7E/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/emTOH31sAqW3piy680Deioyis7E/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=zfQLo0sX71c:jIPp_g1i0cY:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=zfQLo0sX71c:jIPp_g1i0cY:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?i=zfQLo0sX71c:jIPp_g1i0cY:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=zfQLo0sX71c:jIPp_g1i0cY:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=zfQLo0sX71c:jIPp_g1i0cY:V-t1I-SPZMU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=V-t1I-SPZMU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=zfQLo0sX71c:jIPp_g1i0cY:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CatChen/dotNET/~4/zfQLo0sX71c" height="1" width="1"/&gt;</description><feedburner:origLink>http://www.cnblogs.com/cathsfz/archive/2009/08/10/1543266.html</feedburner:origLink></item><item><title>让 JavaScript 轻松支持函数重载 (Part 2 - 实现)</title><link>http://feedproxy.google.com/~r/CatChen/dotNET/~3/BAve2ZtHafc/1515566.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Thu, 02 Jul 2009 07:51:00 GMT</pubDate><guid isPermaLink="false">http://www.cnblogs.com/cathsfz/archive/2009/07/02/1515566.html</guid><description>&lt;p&gt;　　阅读: 2854 评论: 4 作者: &lt;a href="http://www.cnblogs.com/cathsfz/" target="_blank"&gt;Cat Chen&lt;/a&gt; 发表于 2009-07-02 15:51 &lt;a href="http://www.cnblogs.com/cathsfz/archive/2009/07/02/1515566.html" target="_blank"&gt;原文链接&lt;/a&gt;&lt;/p&gt; &lt;p&gt;在&lt;a href="http://www.cnblogs.com/cathsfz/archive/2009/07/02/1515188.html"&gt;上一篇文章&lt;/a&gt;里，我们设计了一套能在JavaScript中描述函数重载的方法，这套方法依赖于一个叫做Overload的静态类，现在我们就来看看如何实现这个静态类。&lt;/p&gt;

&lt;h4&gt;识别文本签名&lt;/h4&gt;

&lt;p&gt;我们先来回顾一下上一篇文章中提到的Overload用例：&lt;/p&gt;

&lt;p&gt;&lt;code&gt; var extend = Overload&lt;br /&gt;&amp;nbsp; .add("*, ...",&lt;br /&gt;&amp;nbsp; &amp;nbsp; function(target) { })&lt;br /&gt;&amp;nbsp; .add("Boolean, *, ...",&lt;br /&gt;&amp;nbsp; &amp;nbsp; function(deep, target) { });&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;我们允许用户输入一个字符串，表示某一个重载的签名。在用户调用函数时，我们需要拿着用户输入的参数实例去跟签名上的每一个参数类型作比较，因此我们需要先把这个字符串转换为类型数组。也就是说，字符串"Boolean, Number, Array"应该转换为数组[Boolean, Number, Array]。&lt;/p&gt;

&lt;p&gt;在进行转换之前，我们先要考虑处理两个特殊类型，就是代表任意类型的"*"，和代表任意数量的"..."。我们可以为它们定义两个专有的类型，以便在Overload内对它们做出特殊的兼容性处理：&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Overload.Any = function() {};&lt;br /&gt;Overload.More = function() {};&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;在有了这两个类型之后，字符串"Boolean, *, ..."就会被正确转换为数组[Boolean, Overload.Any, Overload.More]。由于Overload.Any和Overload.More都是函数，自然也都可以看做类型。&lt;/p&gt;

&lt;p&gt;在这两个类型得到正确处理后，我们就可以开始编写识别文本签名的转换函数了：&lt;/p&gt;

&lt;p&gt;&lt;code&gt;if (signature.replace(/(^\s+|\s+$)/ig, "") == "") {&lt;br /&gt;&amp;nbsp; signature = [];&lt;br /&gt;} else {&lt;br /&gt;&amp;nbsp; signature = signature.split(",");&lt;br /&gt;&amp;nbsp; for (var i = 0; i &amp;lt; signature.length; i++) {&lt;br /&gt;&amp;nbsp; &amp;nbsp; var typeExpression = signature[i].replace(/(^\s+|\s+$)/ig, "");&lt;br /&gt;&amp;nbsp; &amp;nbsp; var type = null;&lt;br /&gt;&amp;nbsp; &amp;nbsp; if (typeExpression == "*") {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; type = Overload.Any;&lt;br /&gt;&amp;nbsp; &amp;nbsp; } else if (typeExpression == "...") {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; type = Overload.More;&lt;br /&gt;&amp;nbsp; &amp;nbsp; } else {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; type = eval("(" + typeExpression + ")");&lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;&amp;nbsp; &amp;nbsp; signature[i] = type;&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;我想这段代码相当容易理解，因此就不再解释了。我第一次写这段代码时忘记写上面的第一个if了，导致空白签名字符串""无法被正确识别为空白签名数组[]，幸好我的unit test代码第一时间发现了这个缺陷。看来编写unit test代码还是十分重要的。&lt;/p&gt;

&lt;h4&gt;匹配函数签名&lt;/h4&gt;

&lt;p&gt;在我们得到函数签名的类型数组后，我们就可以用它和输入参数的实例数组做匹配了，以此找出正确的重载。在讨论具体如何匹配函数签名以前，我们先来看看&lt;a href="http://msdn.microsoft.com/en-us/library/aa691336%28VS.71%29.aspx"&gt;C#&lt;/a&gt;或&lt;a href="http://msdn.microsoft.com/en-us/library/tb18a48w.aspx"&gt;VB.NET&lt;/a&gt;这样的语言是如何处理函数重载匹配的。一般语言进行函数重载匹配的流程都是这样子的：&lt;ol&gt;&lt;li&gt;&lt;strong&gt;参数个数&lt;/strong&gt; - 参数个数不对的重载会被排除掉&lt;/li&gt;&lt;li&gt;&lt;strong&gt;参数类型&lt;/strong&gt; - 参数类型无法隐式转换为签名类型的会被排除掉&lt;/li&gt;&lt;li&gt;&lt;strong&gt;匹配个数&lt;/strong&gt; - 排除完毕后，剩下匹配的签名个数不同处理方法也不同&lt;ul&gt;&lt;li&gt;&lt;strong&gt;0个匹配&lt;/strong&gt; - 没有命中的匹配&lt;/li&gt;&lt;li&gt;&lt;strong&gt;1个匹配&lt;/strong&gt; - 这个就是命中的匹配&lt;/li&gt;&lt;li&gt;&lt;strong&gt;2个或以上的匹配&lt;/strong&gt; - 如果能在这些匹配中找出一个最佳匹配，那就命中最佳匹配；否则不命中任何匹配&lt;/li&gt;&lt;/ul&gt;&lt;/ol&gt;在这一节里面，我们先处理流程中的前两个步骤，把参数个数或参数类型不一致的签名去掉：&lt;/p&gt;

&lt;p&gt;&lt;code&gt;var matchSignature = function(argumentsArray, signature) {&lt;br /&gt;&amp;nbsp; if (argumentsArray.length &amp;lt; signature.length) {&lt;br /&gt;&amp;nbsp; &amp;nbsp; return false;&lt;br /&gt;&amp;nbsp; } else if (argumentsArray.length &gt; signature.length &amp;&amp; !signature.more) {&lt;br /&gt;&amp;nbsp; &amp;nbsp; return false;&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;&amp;nbsp; for (var i = 0; i &amp;lt; signature.length; i++) {&lt;br /&gt;&amp;nbsp; &amp;nbsp; if (!(signature[i] == Overload.Any&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; || argumentsArray[i] instanceof signature[i]&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; || argumentsArray[i].constructor == signature[i])) {&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return false;&lt;br /&gt;&amp;nbsp; &amp;nbsp; }&lt;br /&gt;&amp;nbsp; }&lt;br /&gt;&amp;nbsp; return true;&lt;br /&gt;};&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;为了作长度对比，我们需要在这个函数外对表示任何参数个数的"..."作一下特殊处理：&lt;/p&gt;

&lt;p&gt;&lt;code&gt;if (signature[signature.length - 1] == Overload.More) {&lt;br /&gt;&amp;nbsp; signature.length = signature.length - 1;&lt;br /&gt;&amp;nbsp; signature.more = true;&lt;br /&gt;}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;这一段代码将会整合到第一节的转换函数末端，以便matchSignature函数能够轻易判断出参数与签名是否匹配。在最理想的情况下，我们对输入参数类型匹配到0个或1个重载，这样我们很容易就判断出命中哪个重载了。但如果有2个或以上的重载匹配，那么我们就要从中挑选一个最优的了，这正是下一节要讨论的内容。&lt;/p&gt;

&lt;h4&gt;处理多重匹配&lt;/h4&gt;

&lt;p&gt;关于C#是如何从多重匹配中选出较为匹配的重载，可以看C# Language Specification中的&lt;a href="http://msdn.microsoft.com/en-us/library/aa691338%28VS.71%29.aspx"&gt;有关章节&lt;/a&gt;。我觉得通过三个简单的例子就能说明问题：&lt;/p&gt;

&lt;p&gt;&lt;code&gt; long Sum(int x, int y) { return x + y; }&lt;br /&gt; long Sum(long x, long y) { return x + y; }&lt;br /&gt;Sum(0, 1);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;由于0和1这两个参数会被编译器理解为int类型，对于第1个重载它们都不用进行类型转换，都与第2个重载它们都要进行类型转换，因此第1个重载较优。&lt;/p&gt;

&lt;p&gt;&lt;code&gt; long Sum(int x, long y) { return x + y; }&lt;br /&gt; long Sum(long x, int y) { return x + y; }&lt;br /&gt;Sum(0, 1);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;在第1个参数上，第1个重载较优；在第2个参数上，第2个重载较优。在这种情况下，任何一个重载都不优于另一个，找不到较优重载编译器就报错。&lt;/p&gt;

&lt;p&gt;&lt;code&gt; long Sum(int x, int y) { return x + y; }&lt;br /&gt; long Sum(int x, long y) { return x + y; }&lt;br /&gt; long Sum(long x, int y) { return x + y; }&lt;br /&gt;Sum(0, 1);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;在第1个参数上，第1个重载优于第3个重载，于第2个重载无异；在第2个参数上，第1个重载优于第2个重载，于第3个重载无异。尽管第2个重载于第3个重载分不出个优劣来，但我们可以确定第1个重载比它们都要好，因此编译器选择了第1个重载。&lt;/p&gt;

&lt;p&gt;假设我们有一个overloadComparator的比较函数，可以比较任意两个签名之间的优劣，我们需要对签名仅仅两两比较，以找出最优重载吗？事实上是不需要的，我们可以利用Array的sort方法，让它调用overloadComparator进行排序，排序后再验证前两名的关系就可以了&amp;#8212;&amp;#8212;如果并列，则不命中任何一个；如果有先后之分，则命中第一个。&lt;/p&gt;

&lt;p&gt;具体的overloadComparator代码就不在这里给出了，它依赖于另一个名为inheritanceComparator的比较函数来对比两个签名的参数类型哪一个更贴实际传入的参数类型，里面用到了一种比较巧妙的方法来判断两个类型是否为继承关系，以及是谁继承自谁。&lt;/p&gt;

&lt;h4&gt;小结&lt;/h4&gt;

&lt;p&gt;现在我们有了一个JavaScript的函数重载库，完整代码请看这里：&lt;a href="http://www.cnblogs.com/cathsfz/articles/1515479.html"&gt;函数重载库Overload&lt;/a&gt;。希望这个库能有效帮助大家提升JavaScript代码的可读性，降低大型Ajax项目的维护成本。如果大家希望将来继续读到类似的JavaScript开发模式相关的文章，不妨考虑订阅我的博客：&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://dotnet.catchen.biz/"&gt;Cat in dotNET&lt;/a&gt; (&lt;a href="http://feedproxy.google.com/CatChen/dotNET"&gt;feed&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;&lt;a href="http://chinese.catchen.biz/"&gt;Cat in
Chinese&lt;/a&gt; (&lt;a
href="http://feedproxy.google.com/CatChen/Chinese"&gt;feed&lt;/a&gt;)&lt;/li&gt;&lt;/ul&gt;
 &lt;img src="http://www.cnblogs.com/cathsfz/aggbug/1515566.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;　　&lt;a href="http://www.cnblogs.com/cathsfz/archive/2009/07/02/1515566.html#commentform" target="_blank"&gt;发表评论&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;新闻频道：&lt;a href="http://news.cnblogs.com/n/51086/" target="_blank"&gt;世界银行的公开数据已经出现在 Google 搜索结果中&lt;/a&gt;&lt;/p&gt;&lt;p&gt;推荐链接：&lt;a href="http://kb.cnblogs.com/zt/windows7/" target="_blank"&gt;Windows 7专题发布&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;网站导航：&lt;a href="http://www.cnblogs.com" target="_blank"&gt;博客园首页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://home.cnblogs.com/" target="_blank"&gt;个人主页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://news.cnblogs.com" target="_blank"&gt;新闻&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://space.cnblogs.com" target="_blank"&gt;社区&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://space.cnblogs.com/q/" target="_blank"&gt;博问&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://home.cnblogs.com/ing/" target="_blank"&gt;闪存&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://kb.cnblogs.com" target="_blank"&gt;知识库&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/vovKnvuGDYaO_-PVoYkxC7irdQM/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/vovKnvuGDYaO_-PVoYkxC7irdQM/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/vovKnvuGDYaO_-PVoYkxC7irdQM/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/vovKnvuGDYaO_-PVoYkxC7irdQM/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=BAve2ZtHafc:_St0eitbxsc:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=BAve2ZtHafc:_St0eitbxsc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?i=BAve2ZtHafc:_St0eitbxsc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=BAve2ZtHafc:_St0eitbxsc:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=BAve2ZtHafc:_St0eitbxsc:V-t1I-SPZMU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=V-t1I-SPZMU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=BAve2ZtHafc:_St0eitbxsc:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CatChen/dotNET/~4/BAve2ZtHafc" height="1" width="1"/&gt;</description><feedburner:origLink>http://www.cnblogs.com/cathsfz/archive/2009/07/02/1515566.html</feedburner:origLink></item><item><title>让 JavaScript 轻松支持函数重载 (Part 1 - 设计)</title><link>http://feedproxy.google.com/~r/CatChen/dotNET/~3/0VoLvroIi88/1515188.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Thu, 02 Jul 2009 01:18:00 GMT</pubDate><guid isPermaLink="false">http://www.cnblogs.com/cathsfz/archive/2009/07/02/1515188.html</guid><description>&lt;p&gt;　　阅读: 3128 评论: 11 作者: &lt;a href="http://www.cnblogs.com/cathsfz/" target="_blank"&gt;Cat Chen&lt;/a&gt; 发表于 2009-07-02 09:18 &lt;a href="http://www.cnblogs.com/cathsfz/archive/2009/07/02/1515188.html" target="_blank"&gt;原文链接&lt;/a&gt;&lt;/p&gt;&lt;h4&gt;JavaScript支持重载吗？&lt;/h4&gt;
&lt;p&gt;JavaScript支持函数重载吗？可以说不支持，也可以说支持。说不支持，是因为JavaScript不能好像其它原生支持函数重载的语言一样，直接写多个同名函数，让编译器来判断某个调用对应的是哪一个重载。说支持，是因为JavaScript函数对参数列表不作任何限制，可以在函数内部模拟对函数重载的支持。&lt;/p&gt;
&lt;p&gt;实际上，在很多著名的开源库当中，我们都可以看到函数内部模拟重载支持的设计。例如说jQuery的&lt;a href="http://docs.jquery.com/Utilities/jQuery.extend"&gt;jQuery.extend&lt;/a&gt;方法，就是通过参数类型判断出可选参数是否存在，如果不存在的话就对参数进行移位以确保后面的逻辑正确运行。我相信很多人在写JavaScript时也写过类似的代码，以求为功能丰富的函数提供一个（或多个）简单的调用入口。&lt;/p&gt;
&lt;p&gt;不过做种做法一个根本的问题，那就是违反了&lt;a href="http://en.wikipedia.org/wiki/Don%27t_repeat_yourself"&gt;DRY&lt;/a&gt;原则。每个支持重载的函数内部都多出来一段代码，用于根据参数个数和参数类型处理重载，这些代码暗含着重复的逻辑，写出来却又每一段都不一样。此外，这些代码要维护起来也不容易，因为阅读代码时你并不能一眼看出函数支持的几种重载方式是什么，要对重载做出维护自然也困难。&lt;/p&gt;
&lt;h4&gt;描述重载入口的DSL&lt;/h4&gt;
&lt;p&gt;我希望能够在JavaScript中以一种简单的方式来描述重载入口。最好就如同在其它语言中一样，使用函数签名来区分重载入口，因为我认为函数签名就是这方面最好的&lt;a href="http://en.wikipedia.org/wiki/Domain_specific_language"&gt;DSL&lt;/a&gt;。我假想中最符合JavaScript语法的重载入口描述DSL应该是这样子的：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;var sum = new Overload();&lt;br /&gt;
sum.add("Number, Number",&lt;br /&gt;
&amp;nbsp; function(x, y) { return x + y; });&lt;br /&gt;
sum.add("Number, Number, Number",&lt;br /&gt;
&amp;nbsp; function(x, y, z) { return x + y + z; });&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;在描述好重载入口与对应函数体后，对sum函数的调用应该是这样子的：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;sum(1, 2);&lt;br /&gt;
sum(1, 2, 3);&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;上述代码在我看来非常清晰，也非常容易维护&amp;#8212;&amp;#8212;你可以一眼看得出重载入口的签名，并且要修改或者增加重载入口都是很容易的事情。但是我们遇到了一个问题，那就是JavaScript里面的函数是不能new出来的，通过new Overload()获得的对象一定不能被调用，为此我们只能把Overload做成一个静态类，静态方法返回的是Function实例：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;var sum = Overload&lt;br /&gt;
&amp;nbsp; .add("Number, Number",&lt;br /&gt;
&amp;nbsp; &amp;nbsp; function(x, y) { return x + y; })&lt;br /&gt;
&amp;nbsp; .add("Number, Number, Number",&lt;br /&gt;
&amp;nbsp; &amp;nbsp; function(x, y, z) { return x + y + z; });&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;必要的重载入口支持&lt;/h4&gt;
&lt;p&gt;想象一下，有哪些常见的JavaScript函数入口是用上述DSL无法描述的？我所知道的有两种：&lt;/p&gt;
&lt;h5&gt;任意类型参数&lt;/h5&gt;
&lt;p&gt;假想我们要写一个each函数，对于Array就迭代它的下标，对于其它类型就迭代它的所有成员，这两个函数入口的参数列表如何声明？如果用C#，我们会如此描述两个函数入口：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;void Each(IEnumerable iterator) { }&lt;br /&gt;
void Each(object iterator) { }&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;然而在JavaScript当中，Object不是一切类型的基类，(100) instanceof Object的结果为false，所以我们不能用Object来指代任意类型，必须引入一个新的符号来指代任意类型。考虑到这个符号不应该与任何可能存在的类名冲突，所以我选择了用"*"来表示任意类型。上述C#代码对应的JavaScript应该是这样子的：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;var each = Overload&lt;br /&gt;
&amp;nbsp; .add("Array",&lt;br /&gt;
&amp;nbsp; &amp;nbsp; function(array) { })&lt;br /&gt;
&amp;nbsp; .add("*",&lt;br /&gt;
&amp;nbsp; &amp;nbsp; function(object) { });&lt;/code&gt;&lt;/p&gt;
&lt;h5&gt;任意数量参数&lt;/h5&gt;
&lt;p&gt;在JavaScript的函数里面，要求支持任意数量参数是很常见的需求，相信使用率比C#里面的params关键字要多得多。在我们之前制定的规则当中，这也无法描述的，因此我们要引入一个不和类名冲突的符号来表示C#中的params。我选择了用"..."表示params，意思是这里出现任意多个参数都是可以接受的。让我们看看jQuery.extend的重载应该如何描述：&lt;/p&gt;
&lt;p&gt;&lt;code&gt; var extend = Overload&lt;br /&gt;
&amp;nbsp; .add("*, ...",&lt;br /&gt;
&amp;nbsp; &amp;nbsp; function(target) { })&lt;br /&gt;
&amp;nbsp; .add("Boolean, *, ...",&lt;br /&gt;
&amp;nbsp; &amp;nbsp; function(deep, target) { });&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;小结&lt;/h4&gt;
&lt;p&gt;在这篇文章当中，我们尝试设计出一种适用于JavaScript且易读易维护的函数重载写法。在下一篇文章当中，我们将会尝试编写Overload类，以实现这一设计。如果你不希望错过的话，欢迎订阅：&lt;/p&gt;
&lt;ul&gt;
     &lt;li&gt;&lt;a href="http://dotnet.catchen.biz/"&gt;Cat in dotNET&lt;/a&gt; (&lt;a href="http://feedproxy.google.com/CatChen/dotNET"&gt;feed&lt;/a&gt;)&lt;/li&gt;
     &lt;li&gt;&lt;a href="http://chinese.catchen.biz/"&gt;Cat in
Chinese&lt;/a&gt; (&lt;a
href="http://feedproxy.google.com/CatChen/Chinese"&gt;feed&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;img src="http://www.cnblogs.com/cathsfz/aggbug/1515188.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;　　&lt;a href="http://www.cnblogs.com/cathsfz/archive/2009/07/02/1515188.html#commentform" target="_blank"&gt;发表评论&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;新闻频道：&lt;a href="http://news.cnblogs.com/n/51085/" target="_blank"&gt;Eric Schmidt 解释 Google 为什么收购 AdMob&lt;/a&gt;&lt;/p&gt;&lt;p&gt;推荐链接：&lt;a href="http://kb.cnblogs.com/zt/windows7/" target="_blank"&gt;Windows 7专题发布&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;网站导航：&lt;a href="http://www.cnblogs.com" target="_blank"&gt;博客园首页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://home.cnblogs.com/" target="_blank"&gt;个人主页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://news.cnblogs.com" target="_blank"&gt;新闻&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://space.cnblogs.com" target="_blank"&gt;社区&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://space.cnblogs.com/q/" target="_blank"&gt;博问&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://home.cnblogs.com/ing/" target="_blank"&gt;闪存&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://kb.cnblogs.com" target="_blank"&gt;知识库&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/6GspiNLXOX52_6y7vAZd9Fyd-fA/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/6GspiNLXOX52_6y7vAZd9Fyd-fA/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/6GspiNLXOX52_6y7vAZd9Fyd-fA/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/6GspiNLXOX52_6y7vAZd9Fyd-fA/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=0VoLvroIi88:kIoEMrQjPZM:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=0VoLvroIi88:kIoEMrQjPZM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?i=0VoLvroIi88:kIoEMrQjPZM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=0VoLvroIi88:kIoEMrQjPZM:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=0VoLvroIi88:kIoEMrQjPZM:V-t1I-SPZMU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=V-t1I-SPZMU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=0VoLvroIi88:kIoEMrQjPZM:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CatChen/dotNET/~4/0VoLvroIi88" height="1" width="1"/&gt;</description><feedburner:origLink>http://www.cnblogs.com/cathsfz/archive/2009/07/02/1515188.html</feedburner:origLink></item><item><title>写个 JavaScript 异步调用框架 (Part 6 - 实例 &amp;amp; 模式)</title><link>http://feedproxy.google.com/~r/CatChen/dotNET/~3/uxnKvDCj2Zw/1514983.html</link><dc:creator>Cat Chen</dc:creator><author>Cat Chen</author><pubDate>Wed, 01 Jul 2009 13:59:00 GMT</pubDate><guid isPermaLink="false">http://www.cnblogs.com/cathsfz/archive/2009/07/01/1514983.html</guid><description>&lt;p&gt;　　阅读: 2665 评论: 0 作者: &lt;a href="http://www.cnblogs.com/cathsfz/" target="_blank"&gt;Cat Chen&lt;/a&gt; 发表于 2009-07-01 21:59 &lt;a href="http://www.cnblogs.com/cathsfz/archive/2009/07/01/1514983.html" target="_blank"&gt;原文链接&lt;/a&gt;&lt;/p&gt;&lt;p&gt;我们用了5篇文章来讨论如何编写一个JavaScript异步调用框架（&lt;a target="_blank" href="http://www.cnblogs.com/cathsfz/archive/2009/05/06/1450332.html"&gt;问题 &amp;amp; 场景&lt;/a&gt;、&lt;a target="_blank" href="http://www.cnblogs.com/cathsfz/archive/2009/05/07/1451200.html"&gt;用例设计&lt;/a&gt;、&lt;a target="_blank" href="http://www.cnblogs.com/cathsfz/archive/2009/05/07/1451937.html"&gt;代码实现&lt;/a&gt;、&lt;a target="_blank" href="http://www.cnblogs.com/cathsfz/archive/2009/05/09/1452875.html"&gt;链式调用&lt;/a&gt;、&lt;a target="_blank" href="http://www.cnblogs.com/cathsfz/archive/2009/06/30/1514339.html"&gt;链式实现&lt;/a&gt;），现在是时候让我们看一下在各种常见开发情景中如何使用它了。&lt;/p&gt;
&lt;h4&gt;封装Ajax&lt;/h4&gt;
&lt;p&gt;设计Async.Operation的最初目的就是解决Ajax调用需要传递callback参数的问题，为此我们先把Ajax请求封装为Async.Operation。我在这里使用的是jQuery，当然无论你用什么基础库，在使用Async.Operation时都可以做这种简单的封装。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;var Ajax = {};&lt;br /&gt;
&lt;br /&gt;
Ajax.get = function(url, data) {&lt;br /&gt;
&amp;nbsp; var operation = new Async.Operation();&lt;br /&gt;
&amp;nbsp; $.get(url, data, function(result) { operation.yield(result); }, "json");&lt;br /&gt;
&amp;nbsp; return operation;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
Ajax.post = function(url, data) {&lt;br /&gt;
&amp;nbsp; var operation = new Async.Operation();&lt;br /&gt;
&amp;nbsp; $.post(url, data, function(result) { operation.yield(result); }, "json");&lt;br /&gt;
&amp;nbsp; return operation;&lt;br /&gt;
};&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;在我所调用的服务器端API中，只需要GET和POST，且数据都为JSON，所以我就直接把jQuery提供的其它Ajax选项屏蔽掉了，并设置数据类型为JSON。在你的项目当中，也可以用类似的方式将Ajax封装为若干仅仅返回Async.Operation的方法，将jQuery提供的选项都封装在Ajax这一层内，不再向上层暴露这些选项。&lt;/p&gt;
&lt;h4&gt;调用Ajax&lt;/h4&gt;
&lt;p&gt;把Ajax封装好后，我们就可以开始专心写业务逻辑了。&lt;/p&gt;
&lt;p&gt;假设我们有一个Friend对象，它的get方法用于返回单个好友对象，而getAll方法用于返回所有好友对象。于此对应的是两个服务器端API，friend接口会返回单个好友JSON，而friendlist接口会返回所有好友名称组成的JSON。&lt;/p&gt;
&lt;p&gt;首先我们看看较为基础的get方法怎么写：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;function get(name) {&lt;br /&gt;
&amp;nbsp; return Ajax.get("/friend", "name=" + encodeURIComponent(name));&lt;br /&gt;
}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;就这么简单？对的，假如服务器端API返回的JSON结构正好就是你要的好友对象结构的话。如果JSON结构和好友对象结构是异构的，或许你还要加点代码来把JSON映射为对象：&lt;/p&gt;
&lt;p&gt;&lt;code&gt;function get(name) {&lt;br /&gt;
&amp;nbsp; var operation = new Async.Operation()&lt;br /&gt;
&amp;nbsp; Ajax.get("/friend", "name=" + encodeURIComponent(name))&lt;br /&gt;
&amp;nbsp; &amp;nbsp; .addCallback(function(json) {&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; operation.yield(createFriendFromJson(json));&lt;br /&gt;
&amp;nbsp; &amp;nbsp; });&lt;br /&gt;
&amp;nbsp; return operation;&lt;br /&gt;
}&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;Ajax队列&lt;/h4&gt;
&lt;p&gt;接下来我们要编写的是getAll方法。因为friendlist接口只返回好友名称列表，因此在取得这份列表后我们还要逐一调用get方法获取具体的好友对象。考虑到在同时进行多个friend接口调用可能触发服务器的防攻击策略，导致被关小黑屋一段时间，所以对friend接口的调用必须排队。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;function getAll(){&lt;br /&gt;
&amp;nbsp; var operation = new Async.Operation();&lt;br /&gt;
&amp;nbsp; var friends = [];&lt;br /&gt;
&amp;nbsp; var chain = Async.chain();&lt;br /&gt;
&amp;nbsp; Ajax.get("/friendlist", "")&lt;br /&gt;
&amp;nbsp; &amp;nbsp; .addCallback(function(json) {&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; for (var i = 0; i &amp;lt; json.length; i++) {&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; chain.next(function() {&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return get(json.shift())&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; .addCallback(function(friend) { friends.push(friend); });&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; });&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; chain&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; .next(function() { operation.yield(friends); })&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; .go();&lt;br /&gt;
&amp;nbsp; &amp;nbsp; })&lt;br /&gt;
&amp;nbsp; return operation;&lt;br /&gt;
}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;在这里，我们假设friendlist接口返回的JSON就是一个Array，在获取到这个Array后构造一个等长的异步调用队列，其中每一个调用的逻辑都是一样的&amp;#8212;&amp;#8212;取出Array中首个好友的名称，用get方法获取对应的好友对象，再将好友对象放入另一个Array中。在调用队列的末端，我们再追加了一个调用，用于返回保存好友对象的Array。&lt;/p&gt;
&lt;p&gt;在这个例子当中，我们没有利用调用队列会把上一个函数的结果传递给下一个函数的特性，不过也足够展示调用队列的用途了&amp;#8212;&amp;#8212;让多个底层为Ajax请求的异步操作按照固定的顺序阻塞式执行。&lt;/p&gt;
&lt;p&gt;由于底层异步函数返回的就是Async.Operation，你可以直接把它传递给next方法，也可以用匿名函数包装后传递给next方法，而匿名函数内部只需要一个return。&lt;/p&gt;
&lt;h4&gt;延时函数&lt;/h4&gt;
&lt;p&gt;在上面的例子中，使用队列是为了避免触发服务器的防攻击策略，但有时候这还是不够的。例如说，服务器要求两个请求之间至少间隔500毫秒，否则就认为是攻击，那么我们就要在队列里面插入这个间隔了。&lt;/p&gt;
&lt;p&gt;在原本next方法调用的匿名函数中手动加入setTimeout是一个办法，但为什么我们不写一个辅助函数来解决这类问题呢？让我们来写一个辅助方法并让它和Async.Operation无缝结合起来。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Async.wait = function(delay, context) {&lt;br /&gt;
&amp;nbsp; var operation = new Async.Operation();&lt;br /&gt;
&amp;nbsp; setTimeout(function() { operation.yield(context); }, delay);&lt;br /&gt;
&amp;nbsp; return operation;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
Async.Operation.prototype.wait = function(delay, context) {&lt;br /&gt;
&amp;nbsp; return this.next(function(context) { return Async.wait(delay, context); });&lt;br /&gt;
}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;在有了这个辅助方法后，我们就可以在上述getAll方法中轻松实现在每个Ajax请求之间间隔500毫秒。在for循环内的加上对wait的调用就可以了。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;for (var i = 0; i &amp;lt; json.length; i++) {&lt;br /&gt;
&amp;nbsp; chain&lt;br /&gt;
&amp;nbsp; &amp;nbsp; .wait(500)&lt;br /&gt;
&amp;nbsp; &amp;nbsp; .next(function() {&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; return get(json.shift())&lt;br /&gt;
&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; .addCallback(function(friend) { friends.push(friend); });&lt;br /&gt;
&amp;nbsp; });&lt;br /&gt;
}&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;小结&lt;/h4&gt;
&lt;p&gt;通过一些简单的例子，我们了解到了Async.Operation常见的使用方式，以及在有需要的时候如何扩展它的功能。希望Async.Operation能够有效帮助大家提高Ajax应用的代码可读性。&lt;/p&gt;
&lt;p&gt;最后，如果大家希望将来继续读到类似的JavaScript开发模式相关的文章，不妨考虑订阅我的博客：&lt;/p&gt;
&lt;ul&gt;
     &lt;li&gt;&lt;a target="_blank" href="http://dotnet.catchen.biz/"&gt;Cat in
     dotNET&lt;/a&gt; (&lt;a target="_blank" href="http://feedproxy.google.com/CatChen/dotNET"&gt;feed&lt;/a&gt;)&lt;/li&gt;
     &lt;li&gt;&lt;a target="_blank" href="http://chinese.catchen.biz/"&gt;Cat in Chinese&lt;/a&gt; (&lt;a target="_blank" href="http://feedproxy.google.com/CatChen/Chinese"&gt;feed&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;img src="http://www.cnblogs.com/cathsfz/aggbug/1514983.html?type=1" width="1" height="1" alt=""/&gt;&lt;p&gt;　　&lt;a href="http://www.cnblogs.com/cathsfz/archive/2009/07/01/1514983.html#commentform" target="_blank"&gt;发表评论&lt;/a&gt;&lt;/p&gt;&lt;hr/&gt;&lt;p&gt;新闻频道：&lt;a href="http://news.cnblogs.com/n/51084/" target="_blank"&gt;微软承认Windows7的图形界面偷师苹果Mac OSX&lt;/a&gt;&lt;/p&gt;&lt;p&gt;推荐链接：&lt;a href="http://kb.cnblogs.com/zt/windows7/" target="_blank"&gt;Windows 7专题发布&lt;/a&gt;&lt;br/&gt;&lt;/p&gt;&lt;p&gt;网站导航：&lt;a href="http://www.cnblogs.com" target="_blank"&gt;博客园首页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://home.cnblogs.com/" target="_blank"&gt;个人主页&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://news.cnblogs.com" target="_blank"&gt;新闻&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://space.cnblogs.com" target="_blank"&gt;社区&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://space.cnblogs.com/q/" target="_blank"&gt;博问&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://home.cnblogs.com/ing/" target="_blank"&gt;闪存&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;a href="http://kb.cnblogs.com" target="_blank"&gt;知识库&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://feedads.g.doubleclick.net/~a/dqoJpfNmklbmw1QZQkJu1OcNe10/0/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/dqoJpfNmklbmw1QZQkJu1OcNe10/0/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;br/&gt;
&lt;a href="http://feedads.g.doubleclick.net/~a/dqoJpfNmklbmw1QZQkJu1OcNe10/1/da"&gt;&lt;img src="http://feedads.g.doubleclick.net/~a/dqoJpfNmklbmw1QZQkJu1OcNe10/1/di" border="0" ismap="true"&gt;&lt;/img&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=uxnKvDCj2Zw:6uveq2rKe3U:7Q72WNTAKBA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=7Q72WNTAKBA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=uxnKvDCj2Zw:6uveq2rKe3U:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?i=uxnKvDCj2Zw:6uveq2rKe3U:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=uxnKvDCj2Zw:6uveq2rKe3U:qj6IDK7rITs"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=qj6IDK7rITs" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=uxnKvDCj2Zw:6uveq2rKe3U:V-t1I-SPZMU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=V-t1I-SPZMU" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/CatChen/dotNET?a=uxnKvDCj2Zw:6uveq2rKe3U:dnMXMwOfBR0"&gt;&lt;img src="http://feeds.feedburner.com/~ff/CatChen/dotNET?d=dnMXMwOfBR0" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CatChen/dotNET/~4/uxnKvDCj2Zw" height="1" width="1"/&gt;</description><feedburner:origLink>http://www.cnblogs.com/cathsfz/archive/2009/07/01/1514983.html</feedburner:origLink></item></channel></rss>
