<?xml version="1.0" standalone="yes"?>
<?xml-stylesheet type="text/xsl" href="css/rss.xslt"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>MacGoo - Programer</title><link>http://www.macgoo.com/myblog/</link><description>梦想开始的地方 - </description><generator>RainbowSoft Studio Z-Blog 1.8 Arwen Build 90619</generator><language>zh-CN</language><copyright>Powered By Z-Blog Copyright 2006-2009 Macgoo.com Some Rights Reserved.Theme Design By Design Disease | Transplant by Nobird湘ICP备07001810号var gaJsHost = ((&amp;quot;https:&amp;quot; == document.location.protocol) ? &amp;quot;https://ssl.&amp;quot; : &amp;quot;http://www.&amp;quot;);document.write(unescape(&amp;quot;%3Cscript src='&amp;quot; + gaJsHost + &amp;quot;google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E&amp;quot;));try {var pageTracker = _gat._getTracker(&amp;quot;UA-5293693-2&amp;quot;);pageTracker._trackPageview();} catch(err) {}</copyright><pubDate>Thu, 09 Sep 2010 12:16:51 +0800</pubDate><item><title>EducationSupport项目总结</title><author>soddyque@gmail.com (米落)</author><link>http://www.macgoo.com/myblog/archives/157/</link><pubDate>Tue, 31 Aug 2010 14:12:09 +0800</pubDate><guid>http://www.macgoo.com/myblog/archives/157/</guid><description><![CDATA[<p>&nbsp;&nbsp; &nbsp; 如果说前面的<a target="_blank" href="http://www.macgoo.com/myblog/archives/153/">eWindow</a>是个铺垫的话,这个EducationSupport教学支持项目(下简称ES)则是个尽善尽美不错的作品.</p>
<p>&nbsp;&nbsp; &nbsp; 系统是根据某个比赛的需求,确实,如您所见,这又是个一个参加比赛的项目.在放假的前几天,主办方发给我们一个pdf,上面写着一些模糊的需求,开始我们对其中的很多需求不确定性征求了主办方的意见,就像我们学生组织一样,他们也是再三推脱,然后又回话&quot;自己想&quot;.可想而知比赛是个什么样的形式,所以我都不敢把那比赛说出来.</p>
<p>&nbsp;&nbsp; &nbsp; 由于需求模糊,所以只能自行推敲,结果还好有老师们多年从教经验,而不至于为某个功能的定义大伤脑经.这就是需求.<br />
&nbsp;&nbsp; &nbsp; 在设计里,原来安排的是:<a target="_blank" href="http://dbentry.codeplex.com/">DbEntry.net</a> + ES.Framework + <a target="_blank" href="http://www.asp.net/mvc">ASP.net MVC</a> + <a target="_blank" href="http://www.sencha.com/">Ext</a> ,之类已经上手很多次了,中间除了ES.Framework需要自行实现,ASP.net MVC需要学习,其他的部分都很熟悉了(Ext是上一个项目里实践过了的),不过老师又说这是&quot;微软的比赛&quot;,不得不考虑微软的封闭?(这句话值得商榷),所以尽量用微软的自家产品.于是就有了下面的架构图.</p>
<p>&nbsp;</p>
<p style="text-align: center; "><img onload="ResizeImage(this,520)" alt="" title="" src="http://www.macgoo.com/myblog/attachments/2010/8/201008311617303313.jpg" /></p>
<p style="text-align: left; ">&nbsp;&nbsp; &nbsp;数据层换成了EntityFramework,虽然demo看上去很好用,但为了减少依赖,所以自己在上面封装了一层DataService,它负责EF的调用,以及数据库的开关.业务逻辑做药是权限以及复杂逻辑的实现.表现层则主要是WEB上面的,放弃了原来的Ext,改用jQuery,虽然二者谈不上一个量级,为什么不用ASP.net AJAX ? 学习成本,代码风格,以及jQuery实在是太普及了,微软都首推他.所以我们就用他加上Asp.netMVC带给我们的职责分离,为开发分清思路.</p>
<p style="text-align: left; ">&nbsp;&nbsp; &nbsp;下图为讲解用的幻灯.整个幻灯使用《head first...》系列的风格,以情景剧为模式,涵盖整个项目的分析,设计,编码等等.有人提问,通过一问一答进行描述.将整个过程的难点进行解析.</p>
<p style="text-align: center; "><img onload="ResizeImage(this,520)" alt="" title="" src="http://www.macgoo.com/myblog/attachments/2010/8/201008311623535323.jpg" /></p>
<p style="text-align: left; ">&nbsp;&nbsp; &nbsp; 虽然项目的一些地方可圈可点,不过仍然有些地方表现得令人无法满意.</p>
<ol>
    <li>&nbsp;&nbsp; &nbsp; <strong>没有严格实施日程设计</strong>.如果有一个<a target="_blank" href="http://baike.baidu.com/view/3798770.htm">燃尽图</a>我们的曲线一定是向内凹陷的,尾部时则比原定计划要高.在项目开始时,由于前两次(<a target="_blank" href="http://www.macgoo.com/myblog/archives/153/">eWindow</a>和系网站),所以我觉得面对简单的需求,过多的将时间放在分析上会减少后期编码的时间.所以将设计只给了一个单位时间(一共二十五天,头天是平台框架确定,以后每三天为一个时间单位,每三天一个总结,一个展望),于是在三天内,我们将整个系统的需求就弄出来了,由于需求确实简单,所以这个设计基本上在后面没什么变动,除了在<a target="_blank" href="http://www.cnblogs.com/dreampuf/archive/2010/07/15/Asp_Net_MVC2_PostDataConcurrent.html">完成系统要求的并发性上为数据库添加了一个字段</a>.<br />
    &nbsp;&nbsp; &nbsp; 不过之后的编码,也大大高估了童鞋们的自觉性了,和<a target="_blank" href="http://www.macgoo.com/myblog/archives/153/">eWindow</a>一样,答应好的界面三天出来结果出来了一堆原始HTML元素堆砌的表单,不得不将页面设计由几个主程在后期自己实现,界面既不统一,实现效率也不高(有些地方出现了重复,比如用户的选择-只能选择全部用户不能过滤,JSON的序列化-竟然不知3.5自带的).此后答应好的一个时间单位一个模块,结果是三个单位一个模块,相当于一周就做一个页面,不得不令人汗颜.<br />
    &nbsp;&nbsp; &nbsp; 我当时也心灰意冷,纠结在DataService的实现上.也疏于团队管理,几个测试和文档人员基本上白天来,晚上回去,中午吃饭,压根儿就没交代啥事,我也是维护昨天的一个BUG可能一整天都在纠结.就这样缓缓而进,到了项目结尾.项目开始时交代给文档的PPT也毫无音讯,直到最后一周我再次催促时才去下了几个模板,我的感觉?如临大敌,和<a target="_blank" href="http://www.macgoo.com/myblog/archives/153/">eWindow</a>一样,我仍然会坚持到项目完成为止.<br />
    &nbsp;&nbsp; &nbsp; 这只能说明我团队的规划没有做好,Team Leader果然不能像程序员一样,必须要用更多的时间促进团队的效率,即便自己的任务完成,其他成员的任务也很难令我满意.就像木桶原理的那个桶一样,团队的好与坏不在于最高的那块木板,而是最低的.</li>
    <li>&nbsp;&nbsp; &nbsp; <strong>规范</strong>.在前期就多次提醒要按照规范来,比如底层错误要抛出或者记录日志,前台要try...catch.等等,可事与愿违,这导致了代码进行了反复修改,成员们的心理也造成了很大的波动,每天再三的修改,底层的不确定性(我的失误,开始API的调用就没有将变化抽取出来,导致了<a target="_blank" href="http://www.macgoo.com/myblog/archives/150/">后面进行修改</a>的时候导致了他们的相当的工作量).</li>
    <li>&nbsp;&nbsp; &nbsp;<strong>懒惰</strong>.这主要体现在我后面code review 的时候发现的一些低级错误,你能想象他在view-model设置了一些功能字段,可他的页面就是没有相应的功能,整个表单除了简单的增删改,就没有其他的交互,二十五天就做出这个东西,不能不说态度很有问题.</li>
</ol>
<p>&nbsp;&nbsp; &nbsp; 就这样,这个项目在我回家后的几天里,呕心沥血的完成了,面对其他成员的风格,我改得不是很顺手,有的时候还很无法理解他们这样写的意义,不过都还算是有自己风格的.咱也鼓励&quot;百家齐放&quot;,好歹还是有自己的思考,不是么?项目的最后再幻灯片里的抠图里结束了,托PS cs5的洪福,抠图变得异常简单,我也喜欢上了在图画程序的拖拖拉拉,比编码的逻辑思维,在大脑里的天马行空要心想多啦.</p>
<p>&nbsp;</p>]]></description><category>Programer</category><comments>http://www.macgoo.com/myblog/archives/157/#comment</comments><wfw:comment>http://www.macgoo.com/myblog/</wfw:comment><wfw:commentRss>http://www.macgoo.com/myblog/feed.asp?cmt=157</wfw:commentRss><trackback:ping>http://www.macgoo.com/myblog/cmd.asp?act=tb&amp;id=157&amp;key=9f8ceeaf</trackback:ping></item><item><title>eWindow项目总结</title><author>soddyque@gmail.com (米落)</author><link>http://www.macgoo.com/myblog/archives/153/</link><pubDate>Tue, 10 Aug 2010 21:58:15 +0800</pubDate><guid>http://www.macgoo.com/myblog/archives/153/</guid><description><![CDATA[<p>&nbsp;&nbsp; &nbsp; 这本该是半年以前该做的事了.</p>
<p>&nbsp;&nbsp; &nbsp; 这个项目前前后后折腾了近半年.在项目开始的时候,我在弄一个比赛,在那比赛的时候挺2的,没能夺魁.回来后项目也进行了近一个月.可丝毫没有进展的样子.还只是模模糊糊的画出了数据库设计.<br />
&nbsp;&nbsp; &nbsp; 项目分为三组,开始定好每组五人,结果因为童鞋们兴趣挺浓,就每组多了一人.<span style="background-color: rgb(255, 204, 153); ">整整十八个人,花了半年时间</span>,就折腾出这么个东西,也只想到欲哭无泪这个词儿来形容了.<br />
&nbsp;&nbsp; &nbsp; 项目一开始我也是满心欢喜的参加,由于参加比赛的原因,不能一开始带领大家,于是组长的位置放给了另外一名童鞋.比赛结束之后,因为我个人的一些主张,以及从事风格和他大相径庭,最后是不欢而散,他退出了.他也是一个学习成绩不错的孩子,只可惜还停留在填鸭式的教学上去学习编程.每天完成老师布置的任务,几道哄小孩的题上面,然后看电影,玩游戏荒废光阴.这是题外话了.总之各组之内也出现了人员的调整,这一个小调整就为后面项目的进行造成了不小的阻力.</p>
<p>&nbsp;&nbsp; &nbsp; 项目的进度,十月份开始项目,我十一月过半比完赛参加,中间断断续续的,因为都是鼓捣.Net的,而需求方要求使用J2EE,然后是一些框架的堆砌,Struts2+Hibernate3,这里没有用到Spring,需求方也没提,可能是出于降低项目难度的原因吧,因为依赖倒置之类的抽象理念对于<span style="background-color: rgb(255, 204, 153); ">为什么还要使用类都没琢磨透</span>的童鞋们老说是有那么一点儿不可及.十一月十二月做需求,放寒假的时候还额外留了童鞋们半个多月,半个月前项目都没出来,半个月后都已经定型了,可以说主要的进度都是在这半个月里面出来的.之后来年三月四月修补BUG,最后交稿.</p>
<p>&nbsp;&nbsp; &nbsp; 项目中的问题:<br />
&nbsp;&nbsp; &nbsp; 1.环境问题,说实话,我现在在Eclipse(MyEclipse)下写代码还是有那么些力不从心,各式各样的插件,遍布到处的报错,让人纠结的代码提示(是的,我是被VS惯坏了的孩子),奇怪的调试方式.种种种种的不适.首先是要去找各式各样的插件,而且这些插件由于是开源社区在维护,质量参差不齐,而且由于是在Windows环境下,表现得很是蛋疼.比如说Eclipse下的SVN插件,我已经忘记他的名字了,但是永远都忘不了新接触他的那几天,也让我见识了Xunix下的百家齐放,这个插件可能需要依赖那个插件,而那个插件可能也需要依赖那个.如此往复.版本控制在那时是块心病,就怕哪次更新代码之后错误不断,又要重新来过.不过在几次失败的提交之后导致项目重建,大家都学乖了,要先更新,再提交.这也是一个沟通问题,这点稍后再讲.<br />
&nbsp;&nbsp; &nbsp; 2.态度问题.在项目结束的时候,还有童鞋对HTTP上的交互搞得云里雾里,还对于Session望而生畏.这些在某些培训机构几乎是只教其形而根本不教其意的东西,在他们来说会其形都有困难.打个小差,我在组中也过足了当老师的瘾,因为可以将自己当了十五年学生的经验反馈在我的教学上,好不过瘾,以前看不惯老师的某些手段,在我这里就得意充分更正.对于Session这些我通常是从HTTP无状态的这个设计着手,然后切开,继续深入,最后到为什么需要Session这个东西,在浏览器差异中也从当年的浏览器大战着手,讲的我自己都炮沫横飞,不过却过足了老师的瘾,要是老师们都能有我这样饱汉深情的讲下去何愁朽木不可雕呢?不过后面想想也是,一个老师通常要带两个甚至三个班,教育产业化,将一个东西讲重复一遍两边有可能三遍,而且一年一个循环,谁能受得了,也只有那些园丁们了.这个差有点远了,我们言归正传.在项目中,有很多自以为是的问题,这也许就是程序员们的根病吧.但是倘若没有了这股干劲,又怎样才能从无中生有,作出一个几万行的软件呢?在项目进行时,用了一些管理手段,比如一天一结,然后又是展望,<span style="background-color: rgb(255, 204, 153); ">当然计划无限好</span>(其实还有很多其他模仿着大牛们的例子,但都难以奏效,往往是东施效颦,落得个吃饱了没事干的评价),<span style="background-color: rgb(255, 204, 153); ">只是领导有些小</span>.这些规定对于童鞋们很难有实施的机会,往往他说好了今天完成的任务,其中有些自身无法估计问题大小的原因,还有确实编码能力不够的原因(我已经把模版代码写好了,这下您也懂了,他们是如何&quot;编码&quot;了的吧),可是一周之后可能问题依然没进展,最流行的词儿是&quot;基本上没问题了&quot;,&quot;快可以了&quot;,&quot;只差几个小模块(小函数)就可以了&quot;.唉,我觉得这都能让爱吹的南郭先生笑掉大牙了.<br />
&nbsp;&nbsp; &nbsp;3.项目起因问题,因为这是一个<span style="background-color: rgb(255, 204, 153); ">教学案例项目</span>,这个项目的根本目的不是在于项目是否能成,而且项目本身也只是用于申报国家们的一些&quot;计划&quot;,项目只是让童鞋们学习的,我这里就有些急功近利了,老是觉得自己不该为这样的项目编码那么多,说到底是个心里问题,不过念到自己又通过这个项目掌握了这么多,也不好说些什么,只能是说鱼与熊掌不可兼得吧,可我总觉得如果我把半年时间花在其他的地方上面可能就不是如今这样的了,话说回来谁又没有个&quot;要是当年&quot;呢.项目没有一个好的老师指导,整个进度也就凭我们几个说话没份量的童鞋约束.总而言之,言而总之.这就是一出没谱的戏儿,拿来给戏子们作秀的试验品.<br />
&nbsp;&nbsp; &nbsp;4.贪大喜新.这是我们这组的问题,在前端页面上先独自用上了ExtJS.虽然使用的时候坎坎坷坷,但的出来的效果却是大受好评,而且引得另一组前来学习,不过因为框架学习难度的原因,导致基本上就我们组两个人会用,其他童鞋只能干看着,话说项目开始的时候还是ExtJS3.0,到结束的时候发现更新到了3.1了,直接换框架发现不行,不能兼容,尝试新东西总是要付出代价的.使用ExtJS作为后端表现后,唯独第三组(我们是一组,二组后来也换这个框架了,因为界面问题,始终让人头疼)不愿意更改原来的代码,这里又有一个沟通问题,待会再说.所以导致界面风格迥异,在我们这组的时候可能是标准的ExtJS组件,一旦跳转到三组的页面时,可能就是朴素的HTML了.<br />
&nbsp;&nbsp; &nbsp;5.沟通问题.这也是最根本的问题,如果说依靠我们几个组能写代码的人,加上近半年的时间,而且项目也不是很大,如果沟通良好的话,绝对不是问题.一组擅长前台脚本,二组擅长文档,三组擅长后端编码.这不是配好了的三个桩么.可惜事与愿违.在前面定数据库的时候,<span style="background-color: rgb(255, 204, 153); ">我们都能为一个字段的存在与否争个面红耳赤</span>,在后来为了一个接口的问题还<span style="background-color: rgb(255, 204, 153); ">差点儿罢了工</span>,只能说年轻气盛,没地方发泄啊.互相也是彼此看不起彼此,觉得自己的观点和主见才是正确的.我记得最好笑的是,三组的童鞋把一些验证,以及数据之间关系的绑定都写在了一个Action里,我就指出这有悖分层,表现的逻辑都没分开,实体数据如果不是Hibernate帮忙分离下场可能是JDBC直接写到了Action中.三组的童鞋却一口咬定&quot;这是面向领域编程,和面向对象编程不同&quot;.我当时不懂什么叫&quot;面向领域&quot;,我就说&quot;我不懂什么叫领域,但总不该把这些基本的操作写到页面上去吧.&quot;他却一口咬定.我只能作罢.要是如今碰到,肯定骂他个狗血淋头,&quot;领域你妹啊,那只是一个开发模式,你妹的都把这些八杆子打不着一起的对象写在一起,以后改死你丫的.做三十年代码工人,而且次次项目都重头来过没沉淀.&quot;.唉,年轻气盛.</p>
<p>&nbsp;&nbsp; &nbsp;故事的最后,项目流产了,需求方发现同时操作的项目太多,无暇兼顾,所以就没了下文,我手抖着把项目用QQ邮箱发过去的时候,确实是勾了&quot;回信短信通知&quot;的.可能是没通知到吧.哎哟喔.....</p>
<p>&nbsp;&nbsp; &nbsp;最后是有图有真相.</p>
<p style="text-align: center; "><img onload="ResizeImage(this,520)" alt="" title="" src="http://www.macgoo.com/myblog/attachments/2010/8/201008102319340028.jpg" /><br />
首页<br type="_moz" />
&nbsp;</p>
<p style="text-align: center; "><img onload="ResizeImage(this,520)" alt="" title="" src="http://www.macgoo.com/myblog/attachments/2010/8/201008102316273307.jpg" /><br />
用户订单管理</p>
<p style="text-align: center; ">&nbsp;</p>
<p style="text-align: center; ">&nbsp;</p>
<p>&nbsp;</p>
<p style="text-align: center; "><img onload="ResizeImage(this,520)" alt="" title="" src="http://www.macgoo.com/myblog/attachments/2010/8/201008102317113824.jpg" />登录界面</p>
<p style="text-align: center; ">&nbsp;</p>
<p style="text-align: center; ">&nbsp;</p>
<p>&nbsp;</p>
<p><img onload="ResizeImage(this,520)" alt="" title="" src="http://www.macgoo.com/myblog/attachments/2010/8/201008102317557770.jpg" /><br />
&nbsp;<br />
<img onload="ResizeImage(this,520)" alt="" title="" src="http://www.macgoo.com/myblog/attachments/2010/8/201008102318255518.jpg" /></p>
<p>&nbsp;</p>
<p><img onload="ResizeImage(this,520)" alt="" title="" src="http://www.macgoo.com/myblog/attachments/2010/8/201008102318581454.jpg" /><img onload="ResizeImage(this,520)" alt="" title="" src="http://www.macgoo.com/myblog/attachments/2010/8/201008102319083116.jpg" /><img onload="ResizeImage(this,520)" alt="" title="" src="http://www.macgoo.com/myblog/attachments/2010/8/201008102320091258.jpg" /></p>
<p>&nbsp;</p>
<p><img onload="ResizeImage(this,520)" alt="" title="" src="http://www.macgoo.com/myblog/attachments/2010/8/201008102320345371.jpg" /></p>
<p>&nbsp;</p>]]></description><category>Programer</category><comments>http://www.macgoo.com/myblog/archives/153/#comment</comments><wfw:comment>http://www.macgoo.com/myblog/</wfw:comment><wfw:commentRss>http://www.macgoo.com/myblog/feed.asp?cmt=153</wfw:commentRss><trackback:ping>http://www.macgoo.com/myblog/cmd.asp?act=tb&amp;id=153&amp;key=3310f2d7</trackback:ping></item><item><title>115网盘批量下载</title><author>soddyque@gmail.com (米落)</author><link>http://www.macgoo.com/myblog/archives/151/</link><pubDate>Fri, 06 Aug 2010 15:10:38 +0800</pubDate><guid>http://www.macgoo.com/myblog/archives/151/</guid><description><![CDATA[<p>&nbsp;&nbsp;&nbsp; 第二段是客套,您可以忽略.第三段是说明,您可以一看.第四段是使用方法,是您大概想要的.第五段是下载连接,您最想要的.第六段是源码,您可能会有兴趣.</p>
<p>&nbsp;&nbsp;&nbsp; 如果没有115网盘,大家可能就真的少了接触这么多优秀资源的机会.所以这只是一个辅助程序,您还是要多去115网盘,多点点广告,多支持雨林木风.</p>
<p>&nbsp;&nbsp;&nbsp; 这是一个针对一个页面(或者是一段文字)含有多个115网盘下载链接自动获取真实下载路径的小工具.您可以去联系作者索要更多帮助,他目前很闲(soddyque[at]gmail.com).</p>
<p style="text-align: left;"><span style="background-color: rgb(255, 204, 0);"><span style="font-size: medium;"><span style="font-family: 黑体;">&nbsp;&nbsp;&nbsp; 使用方法:</span></span></span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style="color: rgb(255, 0, 0);">程序需要安装 .Net Framework 3.5 才能使用</span><br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 打开程序后,在[地址输入栏中将还有下载链接的网页的源代码粘贴到内,单击[准备]按钮就能生成连接.如图.<br />
<br />
<img title="" alt="" src="../../attachments/2010/8/201008061518364728.jpg" onload="ResizeImage(this,520)" /><img title="" alt="" src="../../attachments/2010/8/201008061518544743.jpg" onload="ResizeImage(this,520)" /><br />
<br />
&nbsp;&nbsp;&nbsp; 您当然可以选择登录您的115网盘账户后再下载,如果不登录也能同样自动获取,不过<span style="color: rgb(255, 0, 0);">一般网络繁忙的情况下只能获取的到优蛋下载连接</span>.</p>
<p style="text-align: left;"><img title="" alt="" src="../../attachments/2010/8/201008061522426331.jpg" onload="ResizeImage(this,520)" /><img title="" alt="" src="../../attachments/2010/8/201008061522524728.jpg" onload="ResizeImage(this,520)" /></p>
<p style="text-align: left;"><br />
&nbsp;&nbsp;&nbsp; 当获取完毕就能打开程序目录下的以当前时间为名的一个TXT文档,里面就是下载链接.<br />
<br />
<img title="" alt="" src="../../attachments/2010/8/201008061523122567.jpg" onload="ResizeImage(this,520)" /><br />
<br />
&nbsp;&nbsp;&nbsp; 获取到的下载链接,就能够粘贴到迅雷里去批量下载了.<br />
<br />
<img title="" alt="" src="../../attachments/2010/8/201008061523307870.jpg" onload="ResizeImage(this,520)" style="width: 481px; height: 322px;" /><br />
&nbsp;</p>
<p style="text-align: left;"><span style="background-color: rgb(255, 204, 0);"><span style="font-size: medium;"><span style="font-family: 黑体;">&nbsp;&nbsp;&nbsp; 下载地址:</span></span></span></p>
<p><a target="_blank" href="http://www.macgoo.com/myblog/attachments/2010/8/201008061518162604.zip">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 单击下载:&nbsp; 115网盘批量下载.zip</a></p>
<p>&nbsp;</p>
<p><span style="background-color: rgb(255, 204, 0);"><span style="font-size: medium;"><span style="font-family: 黑体;">&nbsp;&nbsp;&nbsp; 程序源码:</span></span></span><br />
&nbsp;&nbsp;&nbsp;&nbsp; 您可以在<a href="http://cid-bfe33abffe41e14a.office.live.com/self.aspx/CodePack/U115CarryOn.zip" target="_blank">这里</a>获取得到程序的所有代码.希望对您有用.</p>]]></description><category>Programer</category><comments>http://www.macgoo.com/myblog/archives/151/#comment</comments><wfw:comment>http://www.macgoo.com/myblog/</wfw:comment><wfw:commentRss>http://www.macgoo.com/myblog/feed.asp?cmt=151</wfw:commentRss><trackback:ping>http://www.macgoo.com/myblog/cmd.asp?act=tb&amp;id=151&amp;key=715f96ad</trackback:ping></item><item><title>EntityFramework v1 .Net3.5 Sp1 动态查询过滤检索所遇到的问题</title><author>soddyque@gmail.com (米落)</author><link>http://www.macgoo.com/myblog/archives/150/</link><pubDate>Fri, 23 Jul 2010 13:07:45 +0800</pubDate><guid>http://www.macgoo.com/myblog/archives/150/</guid><description><![CDATA[<p>&nbsp; &nbsp; 最近在封装EntityFramework的时候碰到许多问题,下面就做一个简短的笔记.&nbsp;</p>
<h2>&nbsp;泛型推断</h2>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 例如Save&lt;T&gt;(T  o)这样的方法是没有问题的,但是如果参数再包裹一层泛型就不行了,Save&lt;T&gt;(IEnumerable&lt;T&gt;  o),所以只能在方法体类判断是否实现了IEnumerable&lt;T&gt;接口,然后分情况处理.<a href="http://stackoverflow.com/questions/407983/c-3-0-generic-type-inference-passing-a-delegate-as-a-function-parameter" target="_blank">关于更多C#3.0中的泛型推断</a>.大体上就是说C#编译器只能推断出明确的一种类型,而不能同时包含多种,比如上面的Save&lt;T&gt;(IEnumerable&lt;T&gt; o)则编译器无法得知参数的具体类型,就需要指定类型.</p>
<h2>&nbsp;拓展方法的访问级别</h2>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 基本上就是一个外部的类,除非在同一程序集里并设定被拓展对象为internal访问级别才能访问,否则protected都访问不到.</p>
<h2>&nbsp; 封装EntityFremawork操作</h2>
<p>&nbsp; &nbsp;&nbsp; 这里主要讲讲查询,一般来说Find方法的签名如下</p>
<pre style="background-color: rgb(240, 240, 240); border: thin ridge rgb(204, 204, 204);" height="400" name="CodeLight_code" class="brush:csharp;mouse-over:#ff9">
public override List&lt;T&gt; Find&lt;T&gt;(int start, int len = 10, IWhereItem&lt;T&gt; whereitem = null, IOrderItem&lt;T&gt; orders = null, bool isDetach = true)</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 起始元素,页长度,过滤语句,排序语句,最后一个是EntityFramework独有,是否与上下文对象解绑.<br />
&nbsp;&nbsp;&nbsp;&nbsp;  在构造ObjectQuery时就需要获得EF的映射关系,用System.Data.Metadata.Edm读取映射信息就可以了,这里我就直接将代 码贴出来了.接受一个EntityContainer就可以不断的读取信息了,本身继承一个见到那的缓存类,实际上就是对字典的一个简单封装.</p>
<pre style="background-color: rgb(240, 240, 240); border: thin ridge rgb(204, 204, 204);" height="400" name="CodeLight_code" class="brush:csharp;mouse-over:#ff9;toolbar:false">
    public class EdmInfo
    {
        public EntitySetBase EntitySetBase { get; set; }
        public string TableName { get; set; }
        public string TypeName { get; set; }
        public string KeyName { get; set; }
    }
    public class EdmInfoManager : SimpleCache&lt;Type, EdmInfo&gt;
    {
        public EntityContainer RootContainer { get; private set; }
        public EdmInfoManager(EntityContainer ec)
        {
            RootContainer = ec;
        }
        public new EdmInfo this[Type T]
        {
            get
            {
                if(!ContainsKey(T))
                {
                    EdmInfo edm = new EdmInfo();
                    edm.EntitySetBase = typeToEntitySetBase(T);
                    edm.TableName = edm.EntitySetBase.Name;
                    edm.TypeName = T.Name;
                    edm.KeyName = entitySetBaseToKeyName(edm.EntitySetBase);
                    base[T] = edm;
                    return edm;
                }
                return base[T];
            }
            set
            {
                base[T] = value;
            }
        }
        private EntitySetBase typeToEntitySetBase(Type t)
        {
            return RootContainer.BaseEntitySets
                       .Where(bes =&gt; bes.ElementType.Name == t.Name)
                       .FirstOrDefault();
        }
        private string entitySetBaseToKeyName(EntitySetBase es)
        {
            return es.ElementType.KeyMembers[0].Name;
        }
    }</pre>
<p>&nbsp;&nbsp;&nbsp;&nbsp;  然后就是排序项,由于项目有一些lambda表达式风格的排序,以及普通属性字符串似的排序,所以又做了一个简单封 装,IOrderItem&lt;T&gt;结构下有两个实现StringOrderItem与ExpressionOrderItem.主要是 StringOrderItem,因为最后都将排序信息保存为字符串了,所以只能以字符串形式排序,这就为后面造成了一些人为的障碍.<br />
&nbsp;&nbsp;&nbsp;&nbsp; 过滤项就是封装了一下Expression&lt;Func&lt;T, bool&gt;&gt;,不过提供从字符串构造的方法.最后都是Lambda表达式的形式存储.<br />
&nbsp;&nbsp;&nbsp;&nbsp; 最后检索的时候就碰到问题了,ObjectQuery.Where(Expression&lt;Func&lt;T,  bool&gt;&gt; exp)是一个拓展方法,返回的不是ObjectQuery,导致了后面无法使用OrderBy(String  orderstring).只能使用OrderBy的拓展方法Lambda表达式形式.卡壳了很久,找了一些资料.其中不乏<a href="http://code.msdn.microsoft.com/EFExtensions" target="_blank">微软的EF拓展库</a>.有个拓展方法能够强制转换为ObjectQuery在链式操作中,但是在我这里一旦强转后面的操作都报错,大概是只支持EFv4吧.</p>
<p>&nbsp; &nbsp; 能否将IWhereItem里的Lambda表达式转为ESQL语句呢?.试着重写一个ExpressionVisitor可惜没功夫没到家,表达式的资料到是找到了不少.就是没写出来.</p>
<p>&nbsp; &nbsp; 表达式的各种构造 :&nbsp;http://rednaxelafx.javaeye.com/blog/247270</p>
<p>&nbsp; &nbsp; LinqToSQL : 一种Linq到TSQL语句的转换,地址忘记了,代码在此 </p>
<p>&nbsp; &nbsp;&nbsp; 在stackoverflow的提问 :&nbsp; http://stackoverflow.com/questions/3305224/problems-with-entity-framework-queries</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 就想把Order转为Lambda表达式形式,但是如何泛型如何设置呢?Expression&lt;Func&lt;T, object&gt;&gt;在面对Expression&lt;Func&lt;T, int&gt;&gt;时会自动有个转换过程,<a href="http://stackoverflow.com/questions/3306964/lambda-expressions-automated-packing" target="_blank">详见Lambda传参自动包装</a>.所以无法直接使用Expression&lt;Func&lt;T, object&gt;&gt;类型传递,在<a href="http://www.blogfor.net/2009/09/03/dynamic-sorting-and-filtering-with-linq-to-sql/" target="_blank">动态构造Linq过滤,排序</a>时发现了一个解决方法,使用<span>IOrderedQueryable</span>包装过滤项,继续搜索,终于找到了使用泛型反射出类型,然后<a href="http://www.codeproject.com/KB/linq/IEnumerableSortByName.aspx?msg=3005452#xx3005452xx" target="_blank">动态构造Lambda表达式(且指定类型)的解决方法了</a>.</p>
<pre style="background-color: rgb(240, 240, 240); border: thin ridge rgb(204, 204, 204);" height="400" name="CodeLight_code" class="brush:csharp;mouse-over:#ff9;toolbar:false">
private static IOrderedEnumerable&lt;T&gt; SortEngine&lt;T&gt;(this IEnumerable&lt;T&gt; source, string columnName, bool isAscending, bool started)
{
    var item = Expression.Parameter(typeof(T), &quot;item&quot;);
    var propertyValue = Expression.PropertyOrField(item, columnName);
    var propertyLambda = Expression.Lambda(propertyValue, item);
    // item =&gt; item.{columnName}
    
    var sourceExpression = Expression.Parameter(typeof(IEnumerable&lt;T&gt;), &quot;source&quot;);

    string methodName;
    Expression inputExpression;
    if (started)
    {
        methodName = isAscending ? &quot;ThenBy&quot; : &quot;ThenByDescending&quot;;
        inputExpression = Expression.Convert(sourceExpression, typeof(IOrderedEnumerable&lt;T&gt;));
        // ThenBy requires input to be IOrderedEnumerable&lt;T&gt;
    }
    else
    {
        methodName = isAscending ? &quot;OrderBy&quot; : &quot;OrderByDescending&quot;;
        inputExpression = sourceExpression;
    }

    var sortTypeParameters = new Type[] { typeof(T), propertyValue.Type };
    var sortExpression = Expression.Call(typeof(Enumerable), methodName, sortTypeParameters, inputExpression, propertyLambda);
    var sortLambda = Expression.Lambda&lt;Func&lt;IEnumerable&lt;T&gt;, IOrderedEnumerable&lt;T&gt;&gt;&gt;(sortExpression, sourceExpression);
    // source =&gt; Enumerable.OrderBy&lt;T, TKey&gt;(source, item =&gt; item.{columnName})
    
    return sortLambda.Compile()(source);
}

public static IOrderedEnumerable&lt;T&gt; OrderBy&lt;T&gt;(this IEnumerable&lt;T&gt; source, string columnName)
{
    return SortEngine(source, columnName, true, false);
}

public static IOrderedEnumerable&lt;T&gt; OrderByDescending&lt;T&gt;(this IEnumerable&lt;T&gt; source, string columnName)
{
    return SortEngine(source, columnName, false, false);
}

public static IOrderedEnumerable&lt;T&gt; ThenBy&lt;T&gt;(this IOrderedEnumerable&lt;T&gt; source, string columnName)
{
    return SortEngine(source, columnName, true, true);
}

public static IOrderedEnumerable&lt;T&gt; ThenByDescending&lt;T&gt;(this IOrderedEnumerable&lt;T&gt; source, string columnName)
{
    return SortEngine(source, columnName, false, true);
}</pre>
<p>&nbsp; &nbsp; 最后Find方法全貌</p>
<pre style="background-color: rgb(240, 240, 240); border: thin ridge rgb(204, 204, 204);" height="400" name="CodeLight_code" class="brush:csharp;mouse-over:#ff9;toolbar:false">
        public override List&lt;T&gt; Find&lt;T&gt;(int start, int len = 10, IWhereItem&lt;T&gt; whereitem = null, IOrderItem&lt;T&gt; orders = null, bool isDetach = true)
        {
            var context = getInstence();
            var edminfo = EdmMgr[typeof (T)];
            ObjectQuery&lt;T&gt; query = context.CreateQuery&lt;T&gt;(&quot;[&quot; + edminfo.TableName + &quot;]&quot;);
            query = MemerVisitor.IncludeMembers.Aggregate(query, (current, str) =&gt; current.Include(str));
            orders = orders ?? OrderItemFactry.Get&lt;T&gt;(edminfo.KeyName, true);
            List&lt;T&gt; result;

            result = whereitem == null || whereitem.Body == null
                         ? start == -1
                               ? query.Skip(orders.OrderString, &quot;0&quot;).ToList()
                               : query.Skip(orders.OrderString, start.ToString()).Take(len).ToList()
                         : start == -1
                               ? query.Skip(orders.OrderString, &quot;0&quot;).Where(whereitem.Body).ToList()
                               : query.Skip(orders.OrderString, &quot;0&quot;).Where(whereitem.Body).OrderBy(orders.Property).Skip(start).Take(len).ToList();

            if (isDetach &amp;&amp; MemerVisitor.IncludeMembers.Count == 0)
                result.ForEach(x =&gt;
                                   {
                                       try
                                       {
                                           context.Detach(x);
                                       }
                                       catch (InvalidOperationException)
                                       {
                                       }
                                   });
            MemerVisitor.IncludeMembers.Clear();
            return result;
        }
</pre>]]></description><category>Programer</category><comments>http://www.macgoo.com/myblog/archives/150/#comment</comments><wfw:comment>http://www.macgoo.com/myblog/</wfw:comment><wfw:commentRss>http://www.macgoo.com/myblog/feed.asp?cmt=150</wfw:commentRss><trackback:ping>http://www.macgoo.com/myblog/cmd.asp?act=tb&amp;id=150&amp;key=dc4262a1</trackback:ping></item><item><title>实现自己的动漫自动下载工具</title><author>soddyque@gmail.com (米落)</author><link>http://www.macgoo.com/myblog/archives/149/</link><pubDate>Sun, 13 Jun 2010 15:43:00 +0800</pubDate><guid>http://www.macgoo.com/myblog/archives/149/</guid><description><![CDATA[<p>&nbsp;</p>
<p style="text-align: center;"><img width="500" height="357" alt="" onload="ResizeImage(this,520)" src="http://www.macgoo.com/myblog/attachments/2010/6/201006131546163714.jpg" /></p>
<p style="text-align: center;">&nbsp;</p>
<p style="text-align: left;">&nbsp; &nbsp; 目的:采集某动漫站点的动漫图片.<br />
&nbsp; &nbsp; 工具: Visual Studio 2010 / 平台: .net Freamwork&nbsp; 2.0 / WinForm</p>
<p style="text-align: left;">&nbsp;</p>
<p style="text-align: left;">&nbsp;&nbsp;&nbsp; 首页 -&gt; 首字母分类 -&gt; 某部动漫 -&gt; 某册 -&gt; 图片集合</p>
<p style="text-align: left;">&nbsp;&nbsp;&nbsp;&nbsp; 抓取思路就是这样,根据不同的页面构造不同的正则匹配即可.整个过程就不多说了,大家都知道.下面分享一些心得.</p>
<ol>
    <li>整个抓取过程具有相当程度的相似性<br />
    &nbsp;&nbsp;&nbsp; 每个部分流程基本上都是获取网页.然后构造 Regex 匹配出结果集合 MatchCollection 对每个匹配集合进行操作获得最终列表,然后可以递归继续操作下一页,也可以返回出与子递归相交的列表集合.<br />
    &nbsp;&nbsp;&nbsp; 所以我们就可以抽取这些相似的部分,然后将不同作为参数传入.当然,这些在后面会提到的.</li>
    <li>对于JavaScript 动态生成列表部分,进行字符串解析或者使用<a href="http://msdn.microsoft.com/zh-cn/library/microsoft.jscript(VS.80).aspx" target="_blank">微软的JScript 引擎</a>解析<br />
    &nbsp;&nbsp;&nbsp; 在我所采集的站点中,使用了JS动态输出图片地址,所以需要一些对JS文本的分析,但在这个项目中没能得到体现,只是普通的正则匹配编码后的地址,然后用翻译后的一个方法去解码.</li>
    <li>多线程调用并不麻烦<br />
    &nbsp;&nbsp;&nbsp; 可能是我使用高版本的开发环境,众所周知,在Visual Studio 2005中如果要进行一个多线程的设计,还需要更改界面显示的话是一件非常繁琐的事情,通常需要新建一个代理,然后在创建一个代理实例,然后再在线程方法中调用该实例.在VS2010中则是简单的一个Linq就可以了.极大的提高了开发效率,这让我写代码的时候都不经意得笑了起来.</li>
    <li>函数的实现多基于&quot;<a href="http://www.ocaml-tutorial.org/%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B" target="_blank">What to do</a>&quot;而尽量避免&quot;How to do&quot;<br />
    &nbsp;&nbsp;&nbsp; 这也是从函数式编程体会到的.现在不都是提倡多写测试用例吗,如果一个函数不能用代码直接断言那么只有人眼能够辨明结果是否是正确的,这是不是也太不&quot;自动&quot;了呢?<br />
    &nbsp;&nbsp;&nbsp; 比如一个读取多个分页将页面信息集合为一个结果列表的方法你是使用while循环呢还是递归调用呢?<br />
    &nbsp;&nbsp;&nbsp; while循环看似直接,但如果需要对这个函数进行测试该如何?这是一个分页列表的读取,自然将测试颗粒度放到一个页面最适合.但是递归则不同,将问题分解,将其他页面的分析递归到下一个函数去而不是下一个循环.到时候仅仅需要对特定层次的调用进行分析就可以了.</li>
    <li>字符串拼接什么时候该用 &quot;+=&quot; 什么时候该用 StringBuilder<br />
    &nbsp;&nbsp;&nbsp; 一个比较好的说明是一定次数内的拼接还是直接用 &quot;+&quot; 操作符就可以了(这里的&quot;次数有不同的说法,有说5次以内的,有说16次以内的).否则就用StringBuilder 效率比较好.<a target="_blank" href="http://www.chinhdo.com/chinh/blog/20070224/stringbuilder-is-not-always-faster/">这里有更详细的讲解</a>,<a target="_blank" href="http://www.chinhdo.com/20070929/stringbuilder-part-2/">详细2</a>.我这里只找到说5次以内的版本,以前有一张图说是16次.总之不同环境应该会有不同的表现,大家自己把握,不过字符串拼接应该不会成为性能瓶颈.所以这一点点吹毛求疵就留给<a target="_blank" href="http://www.macgoo.com/myblog">米落</a>自己把玩吧~</li>
</ol>
<p>&nbsp;&nbsp;&nbsp; 项目不是很OO,所有方法都写在了一个Form窗体类里,这在后面会进行一些设计的.写这个东西花了几个钟头,没有太多的精力,下周还有期末考试和CET4,还有一个微软之星的比赛,总感觉自己像个事儿逼,就爱瞎鼓捣...唉抱怨的话就不多说了.各位自己看吧.</p>
<p>&nbsp;&nbsp;&nbsp; <a target="_blank" href="http://cid-bfe33abffe41e14a.office.live.com/self.aspx/CodePack/BuiltComic.zip">代码下载</a></p>
<p style="text-align: left;"><br />
<br />
&nbsp;</p>]]></description><category>Programer</category><comments>http://www.macgoo.com/myblog/archives/149/#comment</comments><wfw:comment>http://www.macgoo.com/myblog/</wfw:comment><wfw:commentRss>http://www.macgoo.com/myblog/feed.asp?cmt=149</wfw:commentRss><trackback:ping>http://www.macgoo.com/myblog/cmd.asp?act=tb&amp;id=149&amp;key=145bdfd7</trackback:ping></item><item><title>QQ微博自动收听用户</title><author>soddyque@gmail.com (米落)</author><link>http://www.macgoo.com/myblog/archives/148/</link><pubDate>Mon, 31 May 2010 11:54:22 +0800</pubDate><guid>http://www.macgoo.com/myblog/archives/148/</guid><description><![CDATA[<p>
<link href="http://www.macgoo.com/myblog/PLUGIN/Codelight/SyntaxHighlighter/Styles/shCore.css" rel="stylesheet" type="text/css" />
<link href="http://www.macgoo.com/myblog/PLUGIN/Codelight/SyntaxHighlighter/Styles/shThemeDefault.css" rel="stylesheet" type="text/css" /><script language="javascript" src="http://www.macgoo.com/myblog/PLUGIN/Codelight/SyntaxHighlighter/Scripts/shCore.js"></script><script language="javascript" src="http://www.macgoo.com/myblog/PLUGIN/Codelight/SyntaxHighlighter/Scripts/shBrushCSharp.js"></script></p>
<p style="text-align: center;"><img onload="ResizeImage(this,520)" src="http://www.macgoo.com/myblog/attachments/2010/5/201005311242228863.jpg" alt="" title="" /></p>
<p>&nbsp;&nbsp;&nbsp; 闲来无聊,一上午鼓捣点东西.<br />
&nbsp;&nbsp;&nbsp; 自从开通了腾讯微博后希望找找有些出彩的地方,人口基数大就是人口基数大,许多牛人都能出口惊人,可是收听其他用户得一个一个的点,费时费力,于是我就写了个自动添加的偷偷懒.</p>
<p>&nbsp;&nbsp;&nbsp; 登录后获取cookie然后获取自身好友,然后获取每个好友列表,并且查询可以收听的用户(可以判断只添加认证用户),再发出收听请求.Over.简单吧.下面详细分析.</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; 1.登录,我这里用的是WebBrowser,设置URI为 http://t.qq.com/ ,就好了<br />
&nbsp;&nbsp;&nbsp; 2.string2CookieContainer,登录后的WebBrowser对象保存着cookie,这是验证请求是否有效的唯一凭据,所以要保存好了(<a target="_blank" href="http://baike.baidu.com/view/835.htm">更多关于Cookie</a>),后面我们将会使用一个HttpHelper小工具类负责数据交互,他的构造函数包括几个重载形式,其中一个接受CookieContainer 为请求提供凭据.但是WebBrowser里保存的是文本形式,所以我写了一个简单的转换:</p>
<pre class="brush:csharp;mouse-over:#ff9" name="CodeLight_code" height="400" style="background-color: rgb(240, 240, 240); border: thin ridge rgb(204, 204, 204);">
        public static CookieContainer Str2CC(string cookie, Uri uri)
        {
            CookieContainer cc = new CookieContainer();
            string[] temps = cookie.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
            foreach (string str in temps)
            {
                string name = str.Substring(0, str.IndexOf(&quot;=&quot;)).Trim();
                string value = str.Substring(str.IndexOf(&quot;=&quot;) + 1).Trim();
                Cookie c = new Cookie(name, value);
                cc.Add(uri, c);
            }
            return cc;
        }</pre>
<p>&nbsp;&nbsp;&nbsp; 以后的数据交互都通过HttpHelper来进行.</p>
<p>&nbsp;&nbsp;&nbsp; 3.匹配所有好友.<br />
&nbsp;&nbsp;&nbsp; 正则查找出了用户的连接,已经用户名称,并且还补货了一个是否认证的标志,这些在后面的请求中都将会用到的.</p>
<pre class="brush:csharp;mouse-over:#ff9" name="CodeLight_code" height="400" style="background-color: rgb(240, 240, 240); border: thin ridge rgb(204, 204, 204);">
private Regex rg = new Regex(@&quot;&lt;strong&gt;&lt;a href=&quot;&quot;(.+?)&quot;&quot; title=&quot;&quot;.+?\(@(.+?)\)&quot;&quot;&gt;.+?&lt;/a&gt;(&lt;a href=&quot;&quot;/certification&quot;&quot; title=&quot;&quot;腾讯认证&quot;&quot; target=&quot;&quot;_blank&quot;&quot; class=&quot;&quot;vip&quot;&quot;&gt;&lt;/a&gt;)?&lt;/strong&gt;&quot;, RegexOptions.Multiline | RegexOptions.Compiled | RegexOptions.IgnoreCase);
</pre>
<p>&nbsp;&nbsp;&nbsp; 4.发出请求.<br />
&nbsp;&nbsp;&nbsp; 分析了一下QQ微博的收听请求,向 http://t.qq.com/follow.php 发出一个请求,包含两个参数 u 和 r. u是用户名称, r为一个随机数.返回结果为成功,或者今日收听人数上线,我就收到了这两个反馈.</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; 部分代码:</p>
<p>&nbsp;</p>
<p style="text-align: center;"><img onload="ResizeImage(this,520)" src="http://www.macgoo.com/myblog/attachments/2010/5/201005311233060638.jpg" alt="" title="" /></p>
<script language="javascript">SyntaxHighlighter.config.clipboardSwf = 'http://www.macgoo.com/myblog/PLUGIN/Codelight/SyntaxHighlighter/Scripts/clipboard.swf';SyntaxHighlighter.all();</script>]]></description><category>Programer</category><comments>http://www.macgoo.com/myblog/archives/148/#comment</comments><wfw:comment>http://www.macgoo.com/myblog/</wfw:comment><wfw:commentRss>http://www.macgoo.com/myblog/feed.asp?cmt=148</wfw:commentRss><trackback:ping>http://www.macgoo.com/myblog/cmd.asp?act=tb&amp;id=148&amp;key=ac5ec54c</trackback:ping></item><item><title>!+&amp;quot;\v1&amp;quot; 和 !+[1,] 和 !&amp;quot;1&amp;quot;[0] 和 window.attachEvent 和 document.all 比比谁更快</title><author>soddyque@gmail.com (米落)</author><link>http://www.macgoo.com/myblog/archives/144/</link><pubDate>Tue, 02 Feb 2010 00:38:14 +0800</pubDate><guid>http://www.macgoo.com/myblog/archives/144/</guid><description><![CDATA[<p>
<link href="http://www.macgoo.com/myblog/PLUGIN/Codelight/SyntaxHighlighter/Styles/shCore.css" rel="stylesheet" type="text/css" />
<link href="http://www.macgoo.com/myblog/PLUGIN/Codelight/SyntaxHighlighter/Styles/shThemeDefault.css" rel="stylesheet" type="text/css" /><script language="javascript" src="http://www.macgoo.com/myblog/PLUGIN/Codelight/SyntaxHighlighter/Scripts/shCore.js"></script><script language="javascript" src="http://www.macgoo.com/myblog/PLUGIN/Codelight/SyntaxHighlighter/Scripts/shBrushJScript.js"></script></p>
<p>&nbsp;&nbsp;&nbsp; 下面所做的可能有点鸡蛋里跳骨头的味道,但却也十分有趣,希望各位能够在看了之后能够有所收获.</p>
<p>&nbsp;&nbsp;&nbsp; 总所周知,浏览器兼容问题一直困扰着开发者们,勤劳的开发者们也想到了各式各样的小技巧来区分各个派系的浏览器.</p>
<p>&nbsp;&nbsp;&nbsp; !+&quot;\v1&quot;<br />
&nbsp;&nbsp;&nbsp; 这是在园子里的司徒正美童鞋那看到的,第一眼就被震惊了,原来判断可以这样的精悍.<br />
&nbsp;&nbsp;&nbsp; 以下是个人的理解,出处文尾<sup>连接1</sup>.<br />
&nbsp;&nbsp;&nbsp; 这是一个JavaScript类型转换的技巧,按照优先级,这里是从右往左(+ 取正&gt; ! 逻辑求负).也就是将字符串&quot;\v1&quot;转换为数字后再求反.数字求反很好理解,只要不是0的都是true,然后 + 取正对字符串进行了转换,转换为数字.然后IE在这里就出现了歧义,错误的理解了转义符&quot;\v&quot;,垂直制表符,关于制表符在文尾<sup>连接2</sup>有更多的解释.在其他浏览器中能够正确解释这个制表符,IE则将这个制表符解释成了字母&quot;v&quot;,这个当然无法转换成数字,自然转换NaN,按照逻辑操作符的转换规则,转换为了false,再一个求反,则变成了true,趾高气昂的说,&quot;我是IE,没错,TRUE!&quot;.<br />
&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; !+[1,]<br />
&nbsp;&nbsp;&nbsp; 同样是在司徒童鞋那看到的,天天逛园子的收货果然不少啊,关于这个判断语句的解释请移步<a href="http://www.cnblogs.com/rubylouvre/archive/2010/01/28/1658006.html">司徒正美--全 世界最短的IE判定</a> .<br />
&nbsp;&nbsp;&nbsp; 不过在接下来的测试中,你会发现,这条最短的语句不一定是最快的.</p>
<p>&nbsp;&nbsp;&nbsp; <strike>!&quot;1&quot;[0]&nbsp;</strike>&nbsp;&nbsp; <span style="color: rgb(255, 0, 0);"><strong>此方法失效: 详见:</strong></span><a href="http://www.cnblogs.com/dreampuf/archive/2010/02/02/1661444.html#1758968" target="_blank">http://www.cnblogs.com/dreampuf/archive/2010/02/02/1661444.html#1758968<br />
</a> &nbsp;&nbsp;&nbsp; 这个是我翻看Ext源代码时发现的,在Ext.toArray的注释里作者告诉了IE无法使用数组下标访问字符串,这不就又可以分辨了么.<br />
&nbsp;&nbsp;&nbsp; 就是这个方法,IE中无法以数组下标的方式访问字符串,在Ext的注释中提示可以使用&quot;abc&quot;.match(/./g)的方式,我就纳闷了怎么直接使用原生的split方法,&quot;abc&quot;.split(&quot;&quot;),很明显的更直观,而且免去了一个正则的构造.<br />
&nbsp;&nbsp;&nbsp; 这个方法在FF下的效率已经超过了IE.</p>
<p>&nbsp;&nbsp;&nbsp; 至于其他的方法,都是老生长谈的访问某个特殊属性,这里就不多解释了.不过在IE以及FF下访问不存在的属性相差可真大啊.</p>
<table cellspacing="1" cellpadding="1" border="1" align="left" style="width: 600px; height: 366px;">
    <tbody>
        <tr>
            <td colspan="5">IE8</td>
        </tr>
        <tr>
            <td bgcolor="#3399cc"><strong>判断语句</strong></td>
            <td colspan="3"><strong>三次测试</strong></td>
            <td bgcolor="#990033"><strong>平均值</strong></td>
        </tr>
        <tr>
            <td bgcolor="#3399cc">!+&quot;\v1&quot;</td>
            <td>3776</td>
            <td>3682</td>
            <td>3681</td>
            <td bgcolor="#996633">3713</td>
        </tr>
        <tr>
            <td bgcolor="#3399cc">!+[1,]</td>
            <td>58422</td>
            <td>56519</td>
            <td>56581</td>
            <td bgcolor="#996633">57174</td>
        </tr>
        <tr>
            <td bgcolor="#3399cc">!&quot;1&quot;[0]</td>
            <td>5445</td>
            <td>5554</td>
            <td>5507</td>
            <td bgcolor="#996633">5502</td>
        </tr>
        <tr>
            <td bgcolor="#3399cc">!window.addEventListener</td>
            <td>23045</td>
            <td>22825</td>
            <td>22908</td>
            <td bgcolor="#996633">&nbsp;22926</td>
        </tr>
        <tr>
            <td bgcolor="#3399cc">window.attachEvent</td>
            <td>29419</td>
            <td>29450</td>
            <td>29556</td>
            <td bgcolor="#996633">&nbsp;29475</td>
        </tr>
        <tr>
            <td bgcolor="#3399cc">document.all</td>
            <td>44553</td>
            <td>44647</td>
            <td>44835</td>
            <td bgcolor="#996633">&nbsp;44678</td>
        </tr>
        <tr>
            <td colspan="5">&nbsp;</td>
        </tr>
        <tr>
            <td colspan="5">FireFox3.6</td>
        </tr>
        <tr>
            <td bgcolor="#3399cc">!+&quot;\v1&quot;</td>
            <td>&nbsp;1425</td>
            <td>1428</td>
            <td>1425</td>
            <td bgcolor="#996633">&nbsp;1426</td>
        </tr>
        <tr>
            <td bgcolor="#3399cc">!+[1,]</td>
            <td>&nbsp;12627</td>
            <td>12478</td>
            <td>12560</td>
            <td bgcolor="#996633">&nbsp;12555</td>
        </tr>
        <tr>
            <td bgcolor="#3399cc">!&quot;1&quot;[0]</td>
            <td>&nbsp;125</td>
            <td>140</td>
            <td>126</td>
            <td bgcolor="#996633">&nbsp;130</td>
        </tr>
        <tr>
            <td bgcolor="#3399cc">!window.addEventListener</td>
            <td>&nbsp;27236</td>
            <td>25530</td>
            <td>25556</td>
            <td bgcolor="#996633">&nbsp;26107</td>
        </tr>
        <tr>
            <td bgcolor="#3399cc">window.attachEvent</td>
            <td>&nbsp;77590</td>
            <td>79494</td>
            <td>77347</td>
            <td bgcolor="#996633">&nbsp;78143</td>
        </tr>
        <tr>
            <td bgcolor="#3399cc">document.all</td>
            <td>&nbsp;22877</td>
            <td>22984</td>
            <td>22978</td>
            <td bgcolor="#996633">&nbsp;22946</td>
        </tr>
    </tbody>
</table>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; 测试环境 CPU : E2180(2.0GHz),RAM 2G.OS : Win7</p>
<pre class="brush:javascript;mouse-over:#ff9" name="CodeLight_code" height="400" style="background-color: rgb(240, 240, 240); border: thin ridge rgb(204, 204, 204);">
    var i = 0, total = 10000000, btimespan, p1timespan, p2timespan;
    var Bstart = new Date();
    for(;i &lt; total; i++) {
        if(/*测试语句*/) ;
    }
    btimespan = new Date().getTime() - Bstart.getTime();
    
    i = 0;
    var P1start = new Date();
    for(; i &lt; total; i++) {
        if(/*测试语句*/) ;
    }
    p1timespan = new Date().getTime() - P1start.getTime();</pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; 连接1: 32 bytes, ehr ... 9, ehr ... 7!!! to know if your browser is IE -- <a target="_blank" href="http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html">http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html</a>&nbsp; (需翻墙)<br />
&nbsp;&nbsp;&nbsp; 连接2: 转义字符_百度百科 -- <a target="_blank" href="http://baike.baidu.com/view/73.html">http://baike.baidu.com/view/73.html</a><br />
&nbsp;&nbsp;&nbsp; 连接3: JavaScript类型转换 --<a target="_blank" href="http://www.macgoo.com/lib/doc/Javascript_Type_Conversion/Javascript-Type-Conversion.htm"> http://www.macgoo.com/lib/doc/Javascript_Type_Conversion/Javascript-Type-Conversion.htm</a></p>
<script language="javascript">SyntaxHighlighter.config.clipboardSwf = 'http://www.macgoo.com/myblog/PLUGIN/Codelight/SyntaxHighlighter/Scripts/clipboard.swf';SyntaxHighlighter.all();</script>]]></description><category>Programer</category><comments>http://www.macgoo.com/myblog/archives/144/#comment</comments><wfw:comment>http://www.macgoo.com/myblog/</wfw:comment><wfw:commentRss>http://www.macgoo.com/myblog/feed.asp?cmt=144</wfw:commentRss><trackback:ping>http://www.macgoo.com/myblog/cmd.asp?act=tb&amp;id=144&amp;key=1068f486</trackback:ping></item><item><title>在线聊天框界面实现以及控制脚本(不包含与服务端交互)</title><author>soddyque@gmail.com (米落)</author><link>http://www.macgoo.com/myblog/archives/141/</link><pubDate>Wed, 13 Jan 2010 09:23:23 +0800</pubDate><guid>http://www.macgoo.com/myblog/archives/141/</guid><description><![CDATA[<link type="text/css" rel="stylesheet" href="http://www.macgoo.com/myblog/PLUGIN/Codelight/SyntaxHighlighter/Styles/shCore.css" />
<link type="text/css" rel="stylesheet" href="http://www.macgoo.com/myblog/PLUGIN/Codelight/SyntaxHighlighter/Styles/shThemeDefault.css" /><script language="javascript" src="http://www.macgoo.com/myblog/PLUGIN/Codelight/SyntaxHighlighter/Scripts/shCore.js"></script><script language="javascript" src="http://www.macgoo.com/myblog/PLUGIN/Codelight/SyntaxHighlighter/Scripts/shBrushCss.js"></script><script language="javascript" src="http://www.macgoo.com/myblog/PLUGIN/Codelight/SyntaxHighlighter/Scripts/shBrushJScript.js"></script>
<p>&nbsp;&nbsp;&nbsp; 在项目中需要一个在线帮助功能,于是临时设计了一个固定浮动的帮助按钮,在触发后能够弹出一个聊天窗口,确保能在任何页面中都能找到帮助.<br />
&nbsp;&nbsp;&nbsp; 由于需要使用弹出一个聊天窗口,而且站点自身使用了jQuery,于是考虑使用jQuery UI,介于加上了它后的页面变大许多,于是做了一些处理,以便形成惰性加载的效果(只在需要的时候加载页面样式表以及脚本).<br />
&nbsp;&nbsp;&nbsp; 在下面的代码中已经提供了详细的注释,使用时只需要引入这个脚本,和指定的CSS样式表即可.</p>
<p>&nbsp;</p>
<p style="text-align: center;"><img title="" alt="" src="../../attachments/2010/1/201001130938198371.jpg" onload="ResizeImage(this,520)" /><br />
界面如上</p>
<p>&nbsp;</p>
<p>JavaScript 代码:</p>
<pre style="border: thin ridge rgb(204, 204, 204); background-color: rgb(240, 240, 240);" height="400" name="CodeLight_code" class="brush:javascript;mouse-over:#ff9">
var chattingWindow;
(function(){
    var inputContext, showContent, floatDiv;
    chattingWindow = {
        SetUp : function() {
            $(document).ready(function(){
                var cssSrc = &quot;&lt;link rel='stylesheet' type='text/css' href='/css/excite-bike/jquery-ui-1.7.2.custom.css'/&gt;&quot;;    /* CSS样式表 */
                var javascriptSrc = &quot;&lt;script type='text/javascript' src='/javascript/jquery-ui-1.7.2.custom.min.js'&gt;&lt;/script&gt;&quot;;   /* jQuery UI dialog 功能脚本 */
                /* 聊天触发浮动按钮,以及聊天界面HTML */
                var chattingContent = &quot;&lt;div id='chattingWindow'&gt;&lt;img src='images/elementsImages/page_pdf.png' alt='在线咨询' title='在线咨询' /&gt;&lt;/div&gt;&lt;div id='chattingWindowDialog'&gt;&lt;div id='dialogcontent'&gt;&lt;div class='ctitle'&gt;聊天记录&lt;/div&gt;&lt;div id='dialogrender'&gt;&lt;/div&gt;&lt;/div&gt;&lt;div id='dialogintro'&gt;&lt;div class='ctitle'&gt;平安门窗&lt;/div&gt;&lt;p&gt;这里是简介&lt;/p&gt;&lt;/div&gt;&lt;div id='dialoginputs'&gt;&lt;textarea id='dialoginputText' &gt;&lt;/textarea&gt;	&lt;button value='发送' &gt;&lt;img src='/images/global/send_cn.gif' /&gt;&lt;/button&gt;&lt;/div&gt;&lt;div id='dialoglogo'&gt;&lt;/div&gt;&lt;/div&gt;&quot;;
                var inited = false; /* 是否已载入 */
                $(document.body).append(chattingContent);  /* 加入到BODY文档流中去 */
                var floatDiv = $(&quot;#chattingWindow&quot;);     /* 获取引用 */ 
                inputContext = $(&quot;#dialoginputs &gt; textarea&quot;);
                showContent = $(&quot;#dialogrender&quot;);
                showContent.height(250);
                floatDiv.click(function(){  /* 触发弹出窗口页面 */
                    if(!inited) {  /* 第一次使用时的配置工作 */
                        inited = true;
                        $(cssSrc).appendTo(document.body);  /* 引入jQuery UI 样式表,不能删除了,否则后面无法正常显示,可见样式表设置并不会临时保存 */
                        $(javascriptSrc).appendTo(document.body).remove();  /* 引入jQuery UI 脚本,可以删除,因为已经保存在内存中了 */
                        /* diaolog配置 */
                        $(&quot;#chattingWindowDialog&quot;).dialog({autoOpen:false, modal: true, title: &quot;在线客服&quot;, width: 620, height: 470, show: true, hide: true});
                        inputContext.keydown(function(event){  /* 回车按钮事件 */
                        var keycode = event.keyCode || event.which || event.charCode;
                        if(keycode == 13) {
                            chattingWindow.SendMsg(inputContext.val());
                            inputContext.val(&quot;&quot;);
                            return false;
                        }
                    });
                    }
                    $(&quot;#chattingWindowDialog&quot;).dialog(&quot;open&quot;);  /* 打开对话框 */
                });
                $(&quot;#dialoginputs &gt; button&quot;).click(function(){  /* 发送按钮事件 */
                    chattingWindow.SendMsg(inputContext.val());
                    inputContext.val(&quot;&quot;);
                });
                
            });
        },
        SendMsg : function(content) {
            var d = new Date();
            showContent.append(&quot;&lt;div class='send-msg-name'&gt;我 &quot; + (d.getHours() + &quot;:&quot; + d.getMinutes() + &quot;:&quot; + d.getSeconds()) + &quot;&lt;/div&gt;&quot;);
            showContent.append(&quot;&lt;p class='send-msg-content'&gt;&quot; + content + &quot;&lt;/p&gt;&quot;);
            showContent.scrollTop(showContent[0].scrollHeight);
        }
    }
})();
chattingWindow.SetUp();</pre>
<p>&nbsp;</p>
<p>CSS 样式表:</p>
<pre style="border: thin ridge rgb(204, 204, 204); background-color: rgb(240, 240, 240);" height="400" name="CodeLight_code" class="brush:css;mouse-over:#ff9">
#chattingWindow {
	position: fixed;
	bottom: 10px;
	right: 10px;
	
}
#chattingWindow:hover, #chattingWindow a:hover {
	cursor: help;
}
#chattingWindowDialog {
	display: none;
	width: 700px;
	overflow: hidden;
	white-space: normal;
}
div.ctitle {
	background: #06F url(/css/excite-bike/images/ui-bg_diagonals-thick_26_2293f7_40x40.png) repeat left top;
	width: auto;
	height: 24px;
	border: 1px solid #09F;
	overflow: hidden;
}
#dialogcontent {
	width: 450px;
	height: 280px;
	float: left;
	border: 1px solid #09F;
	margin: 2px;
	position: relative;
	overflow: hidden;
}
#dialogrender {
	position: absolute;
	margin-bottom: 5px;
	width: 450px;
	overflow-y: scroll;
	word-break:break-all;
	height: inherit;
}
#dialoginputs {
	width: 450px;
	height: 115px;
	float: left;
	border: 1px solid #09F;
	margin: 2px;
	text-indent:inherit;
}
#dialoginputs textarea {
	float: left;
	border: 0px;
	width: 340px;
	height: 113px;
}
#dialoginputs button {
	float: left;
	border: 0 none;
	background: #FFF;
	margin: 4px;
	width: 100px;
	height: 100px;
}

#dialogintro {
	width: 120px;
	height: 280px;
	border: 1px solid #09F;
	float: left;
	margin: 2px;
}
#dialoglogo {
	width: 120px;
	height: 115px;
	border: 1px solid #09F;
	float: left;
	margin: 2px;
}
.send-msg-name	  {font-family:arial,宋体;font-size:13px;color:#666;font-weight:normal;margin-top:6px}
.send-msg-content {color:#000; }
.recv-msg-content {color:#00f; }</pre>
<p>&nbsp;</p>
<script language="javascript">SyntaxHighlighter.config.clipboardSwf = 'http://www.macgoo.com/myblog/PLUGIN/Codelight/SyntaxHighlighter/Scripts/clipboard.swf';SyntaxHighlighter.all();</script>]]></description><category>Programer</category><comments>http://www.macgoo.com/myblog/archives/141/#comment</comments><wfw:comment>http://www.macgoo.com/myblog/</wfw:comment><wfw:commentRss>http://www.macgoo.com/myblog/feed.asp?cmt=141</wfw:commentRss><trackback:ping>http://www.macgoo.com/myblog/cmd.asp?act=tb&amp;id=141&amp;key=f1828a14</trackback:ping></item><item><title>使用JavaScript 对Cookie 操作的封装</title><author>soddyque@gmail.com (米落)</author><link>http://www.macgoo.com/myblog/archives/139/</link><pubDate>Thu, 31 Dec 2009 17:12:04 +0800</pubDate><guid>http://www.macgoo.com/myblog/archives/139/</guid><description><![CDATA[<div id="dictaudio">&nbsp;通过本篇,您能了解到:</div>
<ul>
    <li>匿名函数</li>
    <li>闭包的产生</li>
    <li>JavaScript实现private 以及 public 访问权限</li>
    <li>document.cookie 的操作</li>
</ul>
<p>&nbsp;</p>
<p>&nbsp; &nbsp; Javascript 没有 private , public 访问权限设置的关键字,但是可以通过一定的技巧来模拟出相同的结果.<br />
&nbsp;&nbsp;&nbsp; 首先我们来看下面一行代码:</p>
<div class="cnblogs_code">
<div><!--<br/ />
<br/ />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />
http://www.CodeHighlighter.com/<br/ />
<br/ />
--><span style="color: rgb(0, 0, 255);">var</span><span style="color: rgb(0, 0, 0);">&nbsp;i&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;(</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">,&nbsp;</span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 0);">,&nbsp;</span><span style="color: rgb(0, 0, 0);">3</span><span style="color: rgb(0, 0, 0);">,&nbsp;</span><span style="color: rgb(0, 0, 0);">4</span><span style="color: rgb(0, 0, 0);">,&nbsp;</span><span style="color: rgb(0, 0, 0);">5</span><span style="color: rgb(0, 0, 0);">);</span></div>
</div>
<p>&nbsp;&nbsp;&nbsp; 变量 i 最后的结果为 5.<br />
&nbsp;&nbsp;&nbsp; 这是逗号操作符的结果,也就是说返回最后的一个值,小括号改变了这行代码的优先级,否则 var i = 1, 2, 3, 4, 5; 会报错缺少标识符.</p>
<div class="cnblogs_code">
<div><!--<br/ />
<br/ />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />
http://www.CodeHighlighter.com/<br/ />
<br/ />
--><span style="color: rgb(0, 0, 255);">var</span><span style="color: rgb(0, 0, 0);">&nbsp;i&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;(</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">,&nbsp;</span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 0);">,&nbsp;</span><span style="color: rgb(0, 0, 0);">3</span><span style="color: rgb(0, 0, 0);">,&nbsp;</span><span style="color: rgb(0, 0, 0);">4</span><span style="color: rgb(0, 0, 0);">,&nbsp;</span><span style="color: rgb(0, 0, 255);">function</span><span style="color: rgb(0, 0, 0);">(){&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">5</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">5</span><span style="color: rgb(0, 0, 0);">;});</span></div>
</div>
<p>&nbsp;&nbsp;&nbsp; 变量 i 最后的结果为 一个函数, 返回结果 25.<br />
&nbsp;&nbsp;&nbsp; 这就是Javascript 的灵活之处,能够赋值任意类型而不必提前声明.现在我们完全可以进行如下调用:</p>
<div class="cnblogs_code">
<div><!--<br/ />
<br/ />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />
http://www.CodeHighlighter.com/<br/ />
<br/ />
--><span style="color: rgb(0, 0, 0);">i();</span> <br />
alert( i() );</div>
</div>
<p>&nbsp;&nbsp;&nbsp; 来获得返回25的一次方法调用.</p>
<p>&nbsp;</p>
<p>&nbsp; &nbsp; 我们继续, 变量 i 是通过赋值符来获取函数的引用的, 也就是说在等号右边的小括号运算完后返回的最后一个结果的引用还在,虽然我们无法显示调用,但它确实存在,如果要不通过变量的引用而调用呢?</p>
<div class="cnblogs_code">
<div><!--<br/ />
<br/ />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />
http://www.CodeHighlighter.com/<br/ />
<br/ />
--><span style="color: rgb(0, 0, 0);">(</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">,&nbsp;</span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 0);">,&nbsp;</span><span style="color: rgb(0, 0, 0);">3</span><span style="color: rgb(0, 0, 0);">,&nbsp;</span><span style="color: rgb(0, 0, 0);">4</span><span style="color: rgb(0, 0, 0);">,&nbsp;</span><span style="color: rgb(0, 0, 255);">function</span><span style="color: rgb(0, 0, 0);">(){&nbsp;&nbsp;&nbsp;&nbsp;alert(</span><span style="color: rgb(0, 0, 0);">5</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">5</span><span style="color: rgb(0, 0, 0);">);})()</span></div>
</div>
<p>&nbsp;&nbsp;&nbsp; 上面的代码执行后,弹出一个消息框,显示25.<br />
&nbsp;&nbsp;&nbsp; 为了显示方便,我将上个例子的函数改为弹出消息框了.<br />
&nbsp;&nbsp;&nbsp; 两对小括号 () (); 前面一对表示返回一个结果,如果该结果为一个函数,由第二对小括号发生调用.<br />
&nbsp;&nbsp;&nbsp; 也就是通过前面一对括号发生匿名函数的引用,以便在下面进行引用.这就是对匿名函数的调用.<br />
&nbsp;&nbsp;&nbsp; 关于更多匿名函数的使用可以参考文尾的引用连接.</p>
<p>&nbsp;</p>
<p>&nbsp; &nbsp; 闭包产生的原因是因为作用域的不同,子作用域引用了父作用域的变量,而返回子作用域,父作用域按理来说执行完毕后该销毁掉了,只是子作用域一直存在,且一直握有父作用域的引用,所以才一直保留.<br />
&nbsp;&nbsp;&nbsp; 来看下面的代码</p>
<pre class="brush:javascript;mouse-over:#ff9" name="CodeLight_code" height="400" style="border: thin ridge rgb(204, 204, 204); background-color: rgb(240, 240, 240);">
function parent() {
    var a = 1;
    function child(){
        var b = 2;
        alert(a);
        alert(b);
    }
}</pre>
<p>&nbsp;&nbsp;&nbsp; 父函数 parent 中包含了一个 child 子函数,在子函数中有一个对父函数中 a 变量的引用(输出其值).<br />
&nbsp;&nbsp;&nbsp; 我们来让父函数执行完后返回其声明的子函数</p>
<pre style="border: thin ridge rgb(204, 204, 204); background-color: rgb(240, 240, 240);" height="400" name="CodeLight_code" class="brush:javascript;mouse-over:#ff9">
function parent() {
    var a = 1;
    function child(){
        var b = 2;
        alert(a);
        alert(b);
    }
    return child;
}
var t = parent();
t();</pre>
<p>&nbsp;&nbsp;&nbsp; 在10行中, 我们执行了parent 函数,返回了在函数内部声明的函数 child,这时变量 t 持有该返回对象(此时是一个可以执行的函数)的引用,在11行代码中我们调用了它.结果分别输出了 1 和 2.<br />
&nbsp;&nbsp;&nbsp; 注意,输出 2, 是因为我们在子函数体内声明了一个变量,而输出 1, 我们在该函数体内并没有相应的定义变量 a ,而是发生了对父函数里的变量的引用,也就是说引用了父作用域的变量.<br />
&nbsp;&nbsp;&nbsp; 而此时又能能够完成输出的,也就是说变量 a 还存在.可是我们无法直接对其引用 (比如 parent.a),因为函数已经执行完毕,没有了其相应的引用,我们只能通过所返回的子函数的引用来进行访问.<br />
&nbsp;&nbsp;&nbsp; 假如我又在父函数中声明了其他的变量呢? 结果是一样的,子函数能够访问,而如果子函数并不返回相应的引用的话,我们根本无法从外部访问到.这就形成了闭包.</p>
<p>&nbsp;</p>
<p>&nbsp; &nbsp; 闭包能够干些什么呢?如果你有一个不想让外部随意修改的变量该怎么做?那就去使用闭包.</p>
<pre style="border: thin ridge rgb(204, 204, 204); background-color: rgb(240, 240, 240);" height="400" name="CodeLight_code" class="brush:javascript;mouse-over:#ff9">
myObj = {};   //声明一个全局变量,它是一个window对象的属性(window.myObj)
(function(){
    var i = 4;
    myObj = {    //引用全局变量,对其进行赋值
        getI : function() {    //get方法,一个函数
            return i;
        },
        setI : function(val) {    //set方法,限制值的设定
            if(val &gt; 100) {
                alert(&quot;i connt &gt; 100&quot;);
                return;
            }
            i = val;
        }
    }
})();    //匿名函数的调用,由于也是一个函数,所以作为一个子作用域,在执行完之后销毁,避免代码污染
myObj.setI(5);  //成功
myObj.setI(101);  //失败
alert(myObj.getI());
alert(myObj.i);  //错误,没有该属性
</pre>
<p>&nbsp; &nbsp; 至此我们简单的实现了public 访问权限以及 private 访问权限 (也就给你想给你的,不给你不想给你的)&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp; 在页面中,我们通常使用 document.cookie 属性来访问,对其赋新值就会创建一个新的Cookie,一个Cookie通常具有五个属性:value (存储的值), date (UTC格式的时间,代表什么时间过期, domain (域,Cookie的所有者), Path (子目录).</p>
<p>&nbsp;&nbsp;&nbsp; 而在平常的开发中,如果仅仅使用 document.cookie 属性进行访问,会很麻烦,因为只能向其赋值字符串,并且在读取后还要进行字符串切割,才能获取指定变量名称的值.document.cookie 读取时,返回的是所有赋值的值,而不包括过期时间,域之类的信息,只能再次独设置.</p>
<p>&nbsp; &nbsp; 下面就附上代码,全部封装到Cookie全局对象中,暴露出几个方法.</p>
<p>&nbsp; &nbsp; Get : 返回指定所有cookie字符串.<br />
&nbsp;&nbsp;&nbsp; Set : 设置cookie 字符串.<br />
&nbsp;&nbsp;&nbsp; Clear : 清除所有cookie对象.<br />
&nbsp;&nbsp;&nbsp; GetDayTime : 获取指定距今val天的Date对象.<br />
&nbsp;&nbsp;&nbsp; Write : 写cookie.已重载.详见代码.<br />
&nbsp;&nbsp;&nbsp; Query : 查询cookie. 已重载.详见代码.<br />
&nbsp;&nbsp;&nbsp; Update : 修改cookie.<br />
&nbsp;&nbsp;&nbsp; Delete : 删除cookie.</p>
<p><pre style="border: thin ridge rgb(204, 204, 204); background-color: rgb(240, 240, 240);" height="400" name="CodeLight_code" class="brush:javascript;mouse-over:#ff9;collapse:true">
Cookie = {};
/*
*   练习总结:
*       Date对象的setTime方法是设置距离1970-01-01以来的毫秒数,设置到对象里去,返回的是据那以后的毫秒数而不是原对象.
*       如果Cookie 不设置 expires 属性,或者expires 时间比本地时间少,那么将会在下一次浏览时过期.
*       document.cookie 对象返回的是所有值的字符串形式,不包含 expires 或者其他.
*
*/
(function() {
    var nDay = 24 * 60 * 60 * 1000;
    var isString = function(v) {
        return typeof v === &quot;string&quot;;
    }
    var isArray = function(v) {
        return Object.prototype.toString.apply(v) == &quot;[object Array]&quot;;
    }
    var isObject = function(v) {
        return v &amp;&amp; typeof v == &quot;object&quot;;
    }
    var isDate = function(v) {
        return Object.prototype.toString.apply(v) == &quot;[object Date]&quot;;
    }
    var getTime = function() {
        return new Date().getTime();
    }
    var trim = function(val) {
        return (val || &quot;&quot;).replace(/^\s+|\s+$/g, &quot;&quot;);
    }
    var tryEval = function(val) {
        var Obj, e;
        try {
            Obj = eval(val);
        } catch (e) {
            Obj = val;
        }
        return Obj;
    }
    var ObjectToString = function(o) {
        var tstr = &quot;{&quot;;
        for (var v in o) {
            if (isArray(o[v])) {
                tstr += v + &quot;:&quot; + ArrayToString(o[v]) + &quot;,&quot;;
            } else if (isObject(o[v])) {
                tstr += v + &quot;:&quot; + ObjectToString(o[v]) + &quot;,&quot;;
            } else if (isString(o[v])) {
                tstr += v + &quot;:\&quot;&quot; + o[v].toString() + &quot;\&quot;,&quot;;
            } else {
                tstr += v + &quot;:&quot; + o[v].toString() + &quot;,&quot;;
            }
        }
        return tstr.slice(0, -1) + &quot;}&quot;;
    }
    var ArrayToString = function(o) {
        var tstr = &quot;[&quot;;
        for (var v in o) {
            if (isArray(o[v])) {
                tstr += ArrayToString(o[v]) + &quot;,&quot;;
            } else if (isObject(o[v])) {
                tstr += ObjectToString(o[v]) + &quot;,&quot;;
            } else {
                tstr += o[v].toString() + &quot;,&quot;;
            }
        }
        return tstr.slice(0, -1) + &quot;]&quot;; ;
    }
    Cookie = {
        Get: function() {
            return document.cookie;
        },
        Set: function(val) {
            document.cookie = val;
        },
        Clear: function() {
            var temp = this.Query();
            var o;
            for (o in temp) {
                this.Delete(o);
            }
        },
        GetDayTime: function(val) {
            var texpires = new Date();
            texpires.setTime(texpires.getTime() + val * nDay);
            return texpires;
        },
        Write: function() {
            /*
            *   Cookie.Write(Object); 写入对象,名称为main;
            *   Cookie.Write(varname, Object); varname:变量名, Object:写入对象;
            *   Cookie.Write(Object, Date); Object:写入对象, Date:过期时间;
            *   Cookie.Write(varname, Object, Date); varname:变量名, Object:写入对象, Date:过期时间;
            *   Cookie.Write(varname, Object, Date, Domain, Path); varname:变量名, Object:写入对象, Date:过期时间, Domain:域, Path: 子目录;
            */
            if (arguments.length == 1) {
                var tvalue = arguments[0];
                var tstr = &quot;&quot;;
                var texpires = new Date(); texpires.setTime(texpires.getTime() + 1 * nDay);
                if (isArray(tvalue)) {
                    tstr = ArrayToString(tvalue);
                } else if (isObject(tvalue)) {
                    tstr = ObjectToString(tvalue);
                } else {
                    tstr = tvalue.toString();
                }
                tstr = &quot;main=&quot; + escape(tstr) + &quot;;expires=&quot; + texpires.toGMTString() + &quot;;&quot;;
            } else if (arguments.length == 2) {
                var tname, tvalue, texpires, tstr = &quot;&quot;;
                if (isDate(arguments[1])) {
                    tname = &quot;main&quot;;
                    tvalue = arguments[0];
                    texpires = arguments[1];
                } else {
                    tname = arguments[0];
                    tvalue = arguments[1];
                    texpires = new Date(); texpires.setTime(texpires.getTime() + 1 * nDay);
                }

                if (isArray(tvalue)) {
                    tstr += ArrayToString(tvalue);
                } else if (isObject(tvalue)) {
                    tstr += ObjectToString(tvalue);
                } else {
                    tstr = tvalue.toString();
                }
                tstr = tname + &quot;=&quot; + escape(tvalue) + &quot;;expires=&quot; + texpires.toGMTString() + &quot;;&quot;;

            } else if (arguments.length == 3) {
                var tname = arguments[0], tvalue = arguments[1], texpires = arguments[2], tstr = &quot;&quot;;
                if (isArray(tvalue)) {
                    tstr = ArrayToString(tvalue);
                } else if (isObject(tvalue)) {
                    tstr = ObjectToString(tvalue);
                } else {
                    tstr = tvalue.toString();
                }
                tstr = tname + &quot;=&quot; + escape(tvalue) + &quot;;expires=&quot; + texpires.toGMTString() + &quot;;&quot;;
            } else if (arguments.length == 5) {
                var tname = arguments[0], tvalue = arguments[1], texpires = arguments[2], tdomain = arguments[3], tpath = arguments[4], tstr = &quot;&quot;;
                if (isArray(tvalue)) {
                    tstr = ArrayToString(tvalue);
                } else if (isObject(tvalue)) {
                    tstr = ObjectToString(tvalue);
                } else {
                    tstr = tvalue.toString();
                }
                tstr = tname + &quot;=&quot; + escape(tvalue) + &quot;;expires=&quot; + texpires.toGMTString() + &quot;;domain=&quot; + tdomain + &quot;;path=&quot; + tpath + &quot;;&quot;;
            }
            alert(tstr);
            this.Set(tstr);
        },
        Query: function() {
            /*
            *   Cookie.Query(); 返回所有Cookie值组成的Object;
            *   Cookie.Query(string); 返回指定名称的Object; 失败则返回 undefined;
            *   Cookie.Query(string, Object); 为指定对象写入指定名称的Object,并返回; 失败则返回 undefined;
            */
            var tname = tvalue = &quot;&quot;, tright = -1;
            var tstr = this.Get();
            var tObj = {};
            if (arguments.length == 0) {
                var i = 0;
                do {
                    tname = trim(tstr.slice(i, tstr.indexOf(&quot;=&quot;, i)));
                    tright = tstr.indexOf(&quot;;&quot;, i);
                    if (tright == -1) {
                        tvalue = unescape(tstr.slice(tstr.indexOf(&quot;=&quot;, i) + 1, tstr.length));
                    } else {
                        tvalue = unescape(tstr.slice(tstr.indexOf(&quot;=&quot;, i) + 1, tright));
                    }
                    tObj[tname] = tryEval(tvalue);
                    i = tstr.indexOf(&quot;;&quot;, i) == -1 ? -1 : tstr.indexOf(&quot;;&quot;, i) + 1;
                } while (i != -1);

            } else {
                tname = arguments[0];
                if (tstr.indexOf(tname) == -1) return undefined;
                var i = tstr.indexOf(tname);
                tname = trim(tstr.slice(i, tstr.indexOf(&quot;=&quot;, i)));
                tright = tstr.indexOf(&quot;;&quot;, tstr.indexOf(tname)) == -1 ? tstr.length : tstr.indexOf(&quot;;&quot;, tstr.indexOf(tname));
                tvalue = unescape(tstr.slice(tstr.indexOf(tname) + tname.length + 1, tright));

                if (arguments.length == 1) {
                    tObj = tryEval(tvalue);
                } else if (arguments.length == 2) {
                    tObj = arguments[1];
                    tObj[tname] = tryEval(tvalue);
                }
            }
            return tObj;
        },
        Update: function() {
            return this.Write.apply(this, arguments);
        },
        Delete: function() {
            if (arguments.length == 1) {
                var varname = arguments[0];
                if (this.Query(varname)) {
                    this.Update(varname, &quot;&quot;, new Date(1970, 01, 01));
                }
            }
        }
    }
})();
//alert(isString(&quot;asd&quot;));
//Cookie.Write([1,{t:1, p:&quot;asdasd&quot;, ary:[1,2,3,45]},3,4,5,6,7,8,9]);
//Cookie.Write(&quot;myvar&quot;, {t:1, p:&quot;asdasd&quot;});
//Cookie.Write(&quot;myvar&quot;, {t:1, p:&quot;asdasd&quot;}, new Date(2009, 12, 31));
//alert(Cookie.Query(&quot;myvar&quot;));
//Cookie.Write(&quot;myvar&quot;, {t:1, p:&quot;asdasd&quot;}, new Date(2009, 12, 31));
//Cookie.Update(&quot;myvar&quot;, {t:1, p:&quot;asdasd&quot;}, new Date(2009, 12, 31));
//Cookie.Write(&quot;myvar&quot;, {t:1, p:&quot;aasdasd&quot;}, Cookie.GetDayTime(5));
//Cookie.Delete(&quot;myvar&quot;);
//alert(Cookie.Query(&quot;main&quot;));</pre></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; 其中有一个从字符串eval 成对象的执行,以及从Object 或者 Array 对象获得对应字符串形式的功能函数,模拟了一些JSON的操作.当然,并不能存储所有的JavaScript 对象,仅仅满足一部分,我已经感觉够用了.</p>
<p>&nbsp;</p>
<p>&nbsp; &nbsp; 个人理解有限,请各位多多指教.</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp; <a target="_blank" href="http://www.cnblogs.com/Files/dreampuf/Cookie.zip" title="Cookie.js.zip">源代码下载 : Cookie.js.zip</a></p>
<p>&nbsp;</p>
<p>Javascript的匿名函数 : <a target="_blank" href="http://dancewithnet.com/2008/05/07/javascript-anonymous-function/">http://dancewithnet.com/2008/05/07/javascript-anonymous-function/ </a> <br />
Javascript 的闭包 : <a target="_blank" href="http://www.cn-cuckoo.com/wordpress/wp-content/uploads/2007/08/JavaScriptClosures.html">http://www.cn-cuckoo.com/wordpress/wp-content/uploads/2007/08/JavaScriptClosures.html</a><br />
Cookie 文件的格式 : <a target="_blank" href="http://www.cnblogs.com/sephil/archive/2008/05/06/cookiefmt.html">http://www.cnblogs.com/sephil/archive/2008/05/06/cookiefmt.html</a></p>]]></description><category>Programer</category><comments>http://www.macgoo.com/myblog/archives/139/#comment</comments><wfw:comment>http://www.macgoo.com/myblog/</wfw:comment><wfw:commentRss>http://www.macgoo.com/myblog/feed.asp?cmt=139</wfw:commentRss><trackback:ping>http://www.macgoo.com/myblog/cmd.asp?act=tb&amp;id=139&amp;key=0972e604</trackback:ping></item><item><title>Visual Studio 2010 beta2 尝鲜</title><author>soddyque@gmail.com (米落)</author><link>http://www.macgoo.com/myblog/archives/138/</link><pubDate>Sat, 26 Dec 2009 19:16:21 +0800</pubDate><guid>http://www.macgoo.com/myblog/archives/138/</guid><description><![CDATA[<p>&nbsp;&nbsp;&nbsp; 微软的Visual Studio 2010 已经发布了 beta2 版了,下载来看试了下味道~</p>
<p>&nbsp;</p>
<p style="text-align: center;"><img style="width: 482px; height: 355px;" onload="ResizeImage(this,520)" src="http://www.macgoo.com/myblog/attachments/2009/12/200912261918433620.jpg" alt="" title="" /><br />
&nbsp;</p>
<p style="text-align: center;">&nbsp;</p>
<p>&nbsp;</p>
<p style="text-align: center;"><img style="width: 482px; height: 287px;" onload="ResizeImage(this,520)" src="http://www.macgoo.com/myblog/attachments/2009/12/200912261919006217.jpg" alt="" title="" /></p>
<p>&nbsp;</p>
<p style="text-align: center;"><img style="width: 564px; height: 388px;" onload="ResizeImage(this,520)" src="http://www.macgoo.com/myblog/attachments/2009/12/200912261919514540.jpg" alt="" title="" /></p>
<p>&nbsp;&nbsp;&nbsp; 新建项目里面相比vs2008多了许多模版,其中比较吸引我的就是MVC,还有Cloud Service .<br />
&nbsp;&nbsp;&nbsp; 由于最近在鼓捣Java , Struts2, Hibernate, 所以自然会拿出来和.Net 这边的比较比较.<br />
&nbsp;&nbsp;&nbsp; Asp.net Mvc 中 Routing 主要起将URL请求转换到指定Control中去,并且通过URL捕获传参,Struts2中是通过 Filter 来启用某个Action.<br />
&nbsp;&nbsp;&nbsp; Asp.net Mvc 中 Control 如其名字一样,控制器,负责将实体模型填充到ViewData或者TempData中去,然后在每个public方法中返回指定视图,并且能够指定名称或者传参.Struts2中 Action 起控制器的作用,Struts2 中获取参数很直接的就在Action的属性里面,传参的话直接添加到request里去就可以了,也很是方便,返回的视图是通过预先约定的name定义好的.<br />
&nbsp;&nbsp;&nbsp; 当然也有一些不同,Struts的每个Action对应的就是一个提交过来的表单,这和Asp.net Mvc里的Control 完全不同,Control 是写在public下的方法中的,两个框架的颗粒度不同,基本上Asp.net Mvc只需要几个Control ,然后根据不同的URL请求来判断该使用那种方法,而可能在一个页面中就有很多个表单提交,这就需要不同的Action 来完成相应的业务.</p>
<p>&nbsp;&nbsp;&nbsp; 还有微软的云 Azure, 虽然还没能写个demo,不过看帮助也能得知个大概,不过貌似相比Google Engine App, Azure需要的配置文件也真的算是多,不知道是不是在Visual Studio舒适的环境待惯了,还是怎么的,都不喜欢那么动辄几个文件的配置了.</p>
<p>&nbsp;&nbsp;&nbsp; 多写代码少说话~</p>]]></description><category>Programer</category><comments>http://www.macgoo.com/myblog/archives/138/#comment</comments><wfw:comment>http://www.macgoo.com/myblog/</wfw:comment><wfw:commentRss>http://www.macgoo.com/myblog/feed.asp?cmt=138</wfw:commentRss><trackback:ping>http://www.macgoo.com/myblog/cmd.asp?act=tb&amp;id=138&amp;key=2dbb1f4e</trackback:ping></item></channel></rss>
