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

<channel>
	<title>YY in Limbo 混沌海狂想 &#187; 代码</title>
	<atom:link href="http://www.limboy.com/category/coder/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.limboy.com</link>
	<description>这里既空虚又充实，没有规则，没有约束，创造来自思考，生存依赖想像，现实源自梦想</description>
	<lastBuildDate>Fri, 07 Oct 2011 19:33:20 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>从事件驱动到observable的异步编程——PubSub+Promise+Rx的JS事件库</title>
		<link>http://www.limboy.com/2011/09/25/pubsub-plus-promise-plus-rx/</link>
		<comments>http://www.limboy.com/2011/09/25/pubsub-plus-promise-plus-rx/#comments</comments>
		<pubDate>Sun, 25 Sep 2011 15:35:39 +0000</pubDate>
		<dc:creator>Dexter.Yy</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[代码]]></category>

		<guid isPermaLink="false">http://www.limboy.com/?p=463</guid>
		<description><![CDATA[你上当叻，虽然从外面看标题很有气势，传达出一种宏大叙事的赶脚，其实我只是刚刚把一个阿尔法城的JS模块提交到github，想顺便介绍一下，但我连API文档都懒得写，就别指望能深入浅出的讲一遍来龙去脉了⋯⋯


所以就直接帖几个前置阅读的链接罢！
这些潮流的外部起源：（技术也有外源论/exogenesis⋯⋯）
Twisted（Python的事件驱动异步引擎）里的Deferred模式
微软推崇的Reactive Extensions (Rx)
虽然我是微软黑但微软网站上的这两篇推介文章不错：
Understanding the Publish/Subscribe Pattern for Greater JavaScript Scalability
Asynchronous Programming in JavaScript with “Promises”
应该都有人翻译了，比如这个：infoQ: JavaScript异步编程的Promise模式
jQuery早就跟微软一个鼻孔出气了：
http://api.jquery.com/category/deferred-object/
CommonJS的Promises提案，照例又分了好多种ABCD神马的：
http://wiki.commonjs.org/wiki/Promises
假如你愿意这里还有一篇paper⋯⋯

阿尔法城的客户端程序里有一个叫作event的模块提供了以上提到的PubSub模式、Promise模式和部分Rx模式，可以算是OzJS的核心module。
就像名字一样，它的初衷是一个最基础最简洁的消息事件库，类似nodejs的EventEmitter。在项目实践中，我很早就注意到可以用统一的事件机制实现Twisted风格的API，为此需要能随时提取事件主题（本质上就是promise对象），后来又根据实际需求加入了能表示状态转移的触发器（enable/resolve）和“一次性”的侦听器（wait/then），最后实现了同时依赖多个异步事件（或promise）的语法工具，包括并发事件（when）和有先后顺序的事件流（follow和end）。所以这个模块不是基于自顶向下的设计，而是在逐步的实践、hack和验证中发展出来的，上面提到的各种模式词汇都是“事后美化”，我觉得大多数“设计模式”也是这样——是对实践方法的归纳和描述，而不是在实践中套用的“新技术”。

开始帖使用范例～

把Event实例单独定义为模块，承担应用各模块之间的消息传递：
oz.def(&#34;notify&#34;, [&#34;event&#34;], function(Event){
&#160; &#160; return&#160;Event(); // 以下例子里省略def/require声明，继续沿用notify和Event这两个局部变量名
});
为基础类生成独立的事件命名空间，不依赖应用级的全局事件：
Dialog.prototype = {
&#160; &#160; init: function(opt){
&#160; &#160; &#160; &#160; this.event = Event();
&#160; &#160; },
&#160; &#160; update: function()&#160;{
&#160; &#160; &#160; &#160; this.updateSize();
&#160; &#160; &#160; &#160; this.updatePosition();
&#160; &#160; &#160; &#160; this.event.fire(&#34;update&#34;, [this]);
&#160; &#160; &#160; &#160; return&#160;this;
&#160; [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://promotejs.com/" target="_blank"><img src="http://www.limboy.com/wp-content/uploads/2011/09/event_18289736.jpeg" style="float:left;margin:0 10px 10px 0;" /></a>你上当叻，虽然从外面看标题很有气势，传达出一种宏大叙事的赶脚，其实我只是刚刚把一个<a target="_blank" href="http://alphatown.com">阿尔法城</a>的JS模块提交到github，想顺便介绍一下，但我连API文档都懒得写，就别指望能深入浅出的讲一遍来龙去脉了⋯⋯<br />
<span id="more-463"></span></p>
<div style="clear:left;"></div>
<p>所以就直接帖几个前置阅读的链接罢！</p>
<p>这些潮流的外部起源：（技术也有外源论/exogenesis⋯⋯）<br />
<a target="_blank" href="http://twistedmatrix.com/documents/current/core/howto/defer.html">Twisted（Python的事件驱动异步引擎）里的Deferred模式</a><br />
<a target="_blank" href="http://msdn.microsoft.com/en-us/data/gg577609">微软推崇的Reactive Extensions (Rx)</a></p>
<p>虽然我是微软黑但微软网站上的这两篇推介文章不错：<br />
<a target="_blank" href="http://msdn.microsoft.com/en-us/scriptjunkie/hh201955">Understanding the Publish/Subscribe Pattern for Greater JavaScript Scalability</a><br />
<a target="_blank" href="http://blogs.msdn.com/b/ie/archive/2011/09/11/asynchronous-programming-in-javascript-with-promises.aspx">Asynchronous Programming in JavaScript with “Promises”</a><br />
应该都有人翻译了，比如这个：<a target="_blank" href="http://www.infoq.com/cn/news/2011/09/js-promise">infoQ: JavaScript异步编程的Promise模式</a></p>
<p>jQuery早就跟微软一个鼻孔出气了：<br />
<a target="_blank" href="http://api.jquery.com/category/deferred-object/">http://api.jquery.com/category/deferred-object/</a></p>
<p>CommonJS的Promises提案，照例又分了好多种ABCD神马的：<br />
<a  target="_blank" href="http://wiki.commonjs.org/wiki/Promises">http://wiki.commonjs.org/wiki/Promises</a></p>
<p><a  target="_blank" href="http://www.cs.brown.edu/%7Esk/Publications/Papers/Published/mgbcgbk-flapjax/">假如你愿意这里还有一篇paper</a>⋯⋯<br />
<br/></p>
<p>阿尔法城的<a  target="_blank" href="http://www.limboy.com/2011/07/10/mvc-behind-alphatown/">客户端程序</a>里有一个叫作<a  target="_blank" href="https://github.com/dexteryy/OzJS/blob/master/mod/event.js">event</a>的模块提供了以上提到的PubSub模式、Promise模式和部分Rx模式，可以算是<a  target="_blank" href="https://github.com/dexteryy/OzJS">OzJS</a>的核心module。</p>
<p>就像名字一样，它的初衷是一个最基础最简洁的消息事件库，类似nodejs的EventEmitter。在项目实践中，我很早就注意到可以用统一的事件机制实现Twisted风格的API，为此需要能随时提取事件主题（本质上就是promise对象），后来又根据实际需求加入了能表示状态转移的触发器（enable/resolve）和“一次性”的侦听器（wait/then），最后实现了同时依赖多个异步事件（或promise）的语法工具，包括并发事件（when）和有先后顺序的事件流（follow和end）。所以这个模块不是基于自顶向下的设计，而是在逐步的实践、hack和验证中发展出来的，上面提到的各种模式词汇都是“事后美化”，我觉得大多数“设计模式”也是这样——是对实践方法的归纳和描述，而不是在实践中套用的“新技术”。<br />
<br/><br />
开始帖使用范例～<br />
<br/></p>
<p>把Event实例单独定义为模块，承担应用各模块之间的消息传递：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">oz</span><span style="color: Gray;">.</span><span style="color: Blue;">def</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">notify</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">event</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">]</span><span style="color: Gray;">, </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">Event</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">Event</span><span style="color: Olive;">()</span><span style="color: Gray;">; </span><span style="color: #ffa500;">// 以下例子里省略def/require声明，继续沿用notify和Event这两个局部变量名</span></li>
<li><span style="color: Olive;">})</span><span style="color: Gray;">;</span></li></ol></div>
<p>为基础类生成独立的事件命名空间，不依赖应用级的全局事件：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">Dialog</span><span style="color: Gray;">.</span><span style="color: Blue;">prototype</span><span style="color: Gray;"> = </span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">init</span><span style="color: Gray;">: </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">opt</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">this</span><span style="color: Gray;">.</span><span style="color: Blue;">event</span><span style="color: Gray;"> = </span><span style="color: Blue;">Event</span><span style="color: Olive;">()</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">update</span><span style="color: Gray;">: </span><span style="color: Green;">function</span><span style="color: Olive;">()</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">this</span><span style="color: Gray;">.</span><span style="color: Blue;">updateSize</span><span style="color: Olive;">()</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">this</span><span style="color: Gray;">.</span><span style="color: Blue;">updatePosition</span><span style="color: Olive;">()</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">this</span><span style="color: Gray;">.</span><span style="color: Blue;">event</span><span style="color: Gray;">.</span><span style="color: Blue;">fire</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">update</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Green;">this</span><span style="color: Olive;">])</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">this</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">,</span></li></ol></div>
<p>监听消息和解除监听：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">notify</span><span style="color: Gray;">.</span><span style="color: Blue;">bind</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">msg:A</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">msg</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">a</span><span style="color: Gray;"> = </span><span style="color: Blue;">msg</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">notify</span><span style="color: Gray;">.</span><span style="color: Blue;">unbind</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">msg:A</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Blue;">arguments</span><span style="color: Gray;">.</span><span style="color: Blue;">callee</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">})</span><span style="color: Gray;">;</span></li></ol></div>
<p>发送消息：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">setTimeout</span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">notify</span><span style="color: Gray;">.</span><span style="color: Blue;">fire</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">msg:A</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">hey jude</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">])</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">}</span><span style="color: Gray;">, </span><span style="color: Maroon;">1000</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li></ol></div>
<p>状态转移：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Gray;">$</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">#button1</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span><span style="color: Blue;">click</span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">e</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">notify</span><span style="color: Gray;">.</span><span style="color: Blue;">resolve</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">button1:clicked</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Green;">this</span><span style="color: Olive;">])</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">notify</span><span style="color: Gray;">.</span><span style="color: Blue;">bind</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">button1:clicked</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">button</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">// 按钮1已经点击过，所以立刻执行</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">button</span><span style="color: Gray;">.</span><span style="color: Blue;">style</span><span style="color: Gray;">.</span><span style="color: Blue;">color</span><span style="color: Gray;"> = </span><span style="color: #8b0000;">'</span><span style="color: Red;">black</span><span style="color: #8b0000;">'</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">})</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">})</span><span style="color: Gray;">;</span></li>
<li><span style="color: Blue;">notify</span><span style="color: Gray;">.</span><span style="color: Blue;">bind</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">button1:clicked</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">button</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: #ffa500;">// 等待按钮1点击之后再执行</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">button</span><span style="color: Gray;">.</span><span style="color: Blue;">style</span><span style="color: Gray;">.</span><span style="color: Blue;">color</span><span style="color: Gray;"> = </span><span style="color: #8b0000;">'</span><span style="color: Red;">red</span><span style="color: #8b0000;">'</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">})</span><span style="color: Gray;">;</span></li></ol></div>
<p>异步回调：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Green;">var</span><span style="color: Gray;"> </span><span style="color: Blue;">data</span><span style="color: Gray;"> = </span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">load</span><span style="color: Gray;">: </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">url</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; $.</span><span style="color: Blue;">getJSON</span><span style="color: Olive;">(</span><span style="color: Blue;">url</span><span style="color: Gray;">, </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">json</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">if</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">(</span><span style="color: Blue;">json</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">notify</span><span style="color: Gray;">.</span><span style="color: Blue;">resolve</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">data:</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> + </span><span style="color: Blue;">url</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">json</span><span style="color: Olive;">])</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">else</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">notify</span><span style="color: Gray;">.</span><span style="color: Blue;">reject</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">data:</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> + </span><span style="color: Blue;">url</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">})</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">notify</span><span style="color: Gray;">.</span><span style="color: Blue;">promise</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">data:</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> + </span><span style="color: Blue;">url</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span></li>
<li><span style="color: Olive;">}</span><span style="color: Gray;">;</span></li>
<li><span style="color: Blue;">data</span><span style="color: Gray;">.</span><span style="color: Blue;">load</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">jsonp_data_1.js</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span><span style="color: Blue;">then</span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">json</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: #ffa500;">// json callback</span></li>
<li><span style="color: Olive;">}</span><span style="color: Gray;">, </span><span style="color: Green;">function</span><span style="color: Olive;">(){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: #ffa500;">// json error </span></li>
<li><span style="color: Olive;">})</span><span style="color: Gray;">;</span></li></ol></div>
<p>也可以用自己的promise对象：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Green;">var</span><span style="color: Gray;"> </span><span style="color: Blue;">promise</span><span style="color: Gray;"> = </span><span style="color: Blue;">Event</span><span style="color: Gray;">.</span><span style="color: Blue;">Promise</span><span style="color: Olive;">()</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">$.</span><span style="color: Blue;">ajax</span><span style="color: Olive;">({</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">url</span><span style="color: Gray;">: </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">jsonp_data_1.js</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">success</span><span style="color: Gray;">: </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">json</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">promise</span><span style="color: Gray;">.</span><span style="color: Blue;">resolve</span><span style="color: Olive;">(</span><span style="color: Blue;">json</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">promise</span><span style="color: Gray;">.</span><span style="color: Blue;">fire</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">json loaded</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">error</span><span style="color: Gray;">: </span><span style="color: Green;">function</span><span style="color: Olive;">(){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">promise</span><span style="color: Gray;">.</span><span style="color: Blue;">reject</span><span style="color: Olive;">()</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">promise</span><span style="color: Gray;">.</span><span style="color: Blue;">error</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">json error</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span></li>
<li><span style="color: Olive;">})</span><span style="color: Gray;">;</span></li>
<li><span style="color: #ffa500;">// fire和error都会执行bind的参数，resolve执行then和bind，所以bind的参数会被执行2次</span></li>
<li><span style="color: #ffa500;">// 如果ajax请求在之前已经返回，则只有then或fail的参数会被执行（因为他们监听的是“状态改变”）</span></li>
<li><span style="color: Blue;">promise</span><span style="color: Gray;">.</span><span style="color: Blue;">bind</span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(){})</span><span style="color: Gray;">.</span><span style="color: Blue;">then</span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(){})</span><span style="color: Gray;">.</span><span style="color: Blue;">fail</span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(){})</span><span style="color: Gray;">;</span></li></ol></div>
<p>事件流：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">notify</span><span style="color: Gray;">.</span><span style="color: Blue;">promise</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">data:jsonp_data_1.js</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span><span style="color: Blue;">then</span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">json</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">setTimeout</span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">notify</span><span style="color: Gray;">.</span><span style="color: Blue;">resolve</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">delay:1000</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Gray;">+</span><span style="color: Green;">new</span><span style="color: Gray;">&nbsp;</span><span style="color: Teal;">Date</span><span style="color: Olive;">()</span><span style="color: Gray;">, </span><span style="color: Blue;">json</span><span style="color: Olive;">])</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">, </span><span style="color: Maroon;">1000</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">notify</span><span style="color: Gray;">.</span><span style="color: Blue;">promise</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">delay:1000</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">})</span><span style="color: Gray;">.</span><span style="color: Blue;">follow</span><span style="color: Olive;">()</span><span style="color: Gray;">.</span><span style="color: Blue;">then</span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">time</span><span style="color: Gray;">, </span><span style="color: Blue;">json</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">setTimeout</span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">console</span><span style="color: Gray;">.</span><span style="color: Blue;">log</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">[数据在3秒前加载成功]</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Blue;">json</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">, </span><span style="color: Maroon;">2000</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">})</span><span style="color: Gray;">.</span><span style="color: Blue;">end</span><span style="color: Olive;">()</span><span style="color: Gray;">.</span><span style="color: Blue;">fail</span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">msg</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">notify</span><span style="color: Gray;">.</span><span style="color: Blue;">promise</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">data:error</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span><span style="color: Blue;">resolve</span><span style="color: Olive;">([</span><span style="color: Blue;">msg</span><span style="color: Olive;">])</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">})</span><span style="color: Gray;">.</span><span style="color: Blue;">follow</span><span style="color: Olive;">()</span><span style="color: Gray;">.</span><span style="color: Blue;">then</span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">console</span><span style="color: Gray;">.</span><span style="color: Blue;">log</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">[数据加载失败]</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Blue;">msg</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">})</span><span style="color: Gray;">;</span></li></ol></div>
<p>避免多层的回调嵌套（“callback hell”）：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Green;">var</span><span style="color: Gray;"> </span><span style="color: Blue;">fs</span><span style="color: Gray;"> = </span><span style="color: Blue;">require</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">fs</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Blue;">fs</span><span style="color: Gray;">.</span><span style="color: Blue;">readFile</span><span style="color: Olive;">(</span><span style="color: Blue;">input</span><span style="color: Gray;">, </span><span style="color: #8b0000;">'</span><span style="color: Red;">utf-8</span><span style="color: #8b0000;">'</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span><span style="color: Blue;">then</span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">err</span><span style="color: Gray;">, </span><span style="color: Blue;">data</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">beautifuldata</span><span style="color: Gray;"> = </span><span style="color: Blue;">js_beautify</span><span style="color: Olive;">(</span><span style="color: Blue;">data</span><span style="color: Gray;">, </span><span style="color: Blue;">options</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: #ffa500;">// 需要修改readFile和writeFile传出promise对象</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">fs</span><span style="color: Gray;">.</span><span style="color: Blue;">writeFile</span><span style="color: Olive;">(</span><span style="color: Blue;">output</span><span style="color: Gray;">, </span><span style="color: Blue;">beautifuldata</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">})</span><span style="color: Gray;">.</span><span style="color: Blue;">follow</span><span style="color: Olive;">()</span><span style="color: Gray;">.</span><span style="color: Blue;">then</span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">err</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">if</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">(</span><span style="color: Blue;">err</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">throw</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">err</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">console</span><span style="color: Gray;">.</span><span style="color: Blue;">log</span><span style="color: Olive;">(</span><span style="color: #8b0000;">'</span><span style="color: Red;">Success!</span><span style="color: #8b0000;">'</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">})</span><span style="color: Gray;">;</span></li></ol></div>
<p>依赖多个并发事件：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">notify</span><span style="color: Gray;">.</span><span style="color: Blue;">when</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">msg:A</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">msg:B</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">jsonp:A</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">jsonp:B</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: #ffa500;">// when传出新的promise对象</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; .</span><span style="color: Blue;">some</span><span style="color: Olive;">(</span><span style="color: Maroon;">3</span><span style="color: Olive;">)</span><span style="color: Gray;">&nbsp;</span><span style="color: #ffa500;">// 如果不调用some或any，默认为全部事件完成后再触发resolve </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; .</span><span style="color: Blue;">then</span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(){</span><span style="color: Gray;">&nbsp;</span><span style="color: #ffa500;">// 已经取到3/4的数据，参数顺序跟when的参数顺序一样</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">console</span><span style="color: Gray;">.</span><span style="color: Blue;">warn</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">recieve 3/4</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Blue;">arguments</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">})</span><span style="color: Gray;">;</span></li></ol></div>
<p>静态方法Event.when接受promise参数，可以写出更复杂的依赖关系：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">Event</span><span style="color: Gray;">.</span><span style="color: Blue;">when</span><span style="color: Olive;">(</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">notify</span><span style="color: Gray;">.</span><span style="color: Blue;">when</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">msg:A</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">msg:B</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)</span><span style="color: Gray;">, </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">notify</span><span style="color: Gray;">.</span><span style="color: Blue;">when</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">click:btn1</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">clicked:btn2</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span><span style="color: Blue;">any</span><span style="color: Olive;">()</span></li>
<li><span style="color: Olive;">)</span><span style="color: Gray;">.</span><span style="color: Blue;">then</span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">args1</span><span style="color: Gray;">, </span><span style="color: Blue;">args2</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: #ffa500;">// 相当于：&quot;msg:A&quot; &amp;&amp; &quot;msg:B&quot; &amp;&amp; ( &quot;click:btn1&quot; || &quot;clicked:btn2&quot; )</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">console</span><span style="color: Gray;">.</span><span style="color: Blue;">warn</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">recieve all messages, click one button</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Blue;">arguments</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">})</span><span style="color: Gray;">;</span></li></ol></div>
<p><br/><br />
测试demo：<a  target="_blank" href="https://github.com/dexteryy/OzJS/blob/master/tests/test_event.html">https://github.com/dexteryy/OzJS/blob/master/tests/test_event.html</a><br />
可以在console里观察执行顺序⋯⋯</p>
<p>从这个测试页可以看出我连单元测试都懒得写⋯⋯<br />
<br/></p>
]]></content:encoded>
			<wfw:commentRss>http://www.limboy.com/2011/09/25/pubsub-plus-promise-plus-rx/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>被遗忘的vim插件管理程序⋯⋯</title>
		<link>http://www.limboy.com/2011/09/25/vim-plugin-scaner/</link>
		<comments>http://www.limboy.com/2011/09/25/vim-plugin-scaner/#comments</comments>
		<pubDate>Sun, 25 Sep 2011 14:56:17 +0000</pubDate>
		<dc:creator>Dexter.Yy</dc:creator>
				<category><![CDATA[Python]]></category>
		<category><![CDATA[工具]]></category>

		<guid isPermaLink="false">http://www.limboy.com/?p=454</guid>
		<description><![CDATA[众所周知vim缺少官方的包管理机制，刚开始接触vim的人往往都有IDE情结，喜欢四处搜罗插件，光是ftplugin目录就要塞进十几个脚本，把“编辑器之神”武装得包罗万象无所不能，然而这些卑微的凡人，尽管手握神器，总归还是要身陷在繁忙的日常coding中，最初的欣喜和热情也在日复一日中消散，由于没有定期更新这些脚本文件的办法，更没有精力去逐个关注，渐渐就忘记了兼容性升级，忘记了:com，忘记了键位映射，忘记了操作符，最后可能连插件名字和功能都记不得了⋯⋯
好罢这不是那种“我有一个朋友”式的故事，我只是想说一个自动化的插件管理程序能解决这种维护烦恼，起码不至于等到世界变了OS都升级了出现严重兼容性问题了编辑器都启动不了之后再去排查原因移除长久不用的插件⋯⋯
这本书告诉我们技术不是孤立发展的，当你察觉到一种需求的时候，意味着大半个开发者社区都有了这种需求，当你被逼得动手尝试idea，意味着同类项目已经更新了一个大版本，所以说当前比较完善的vim包管理工具大概有以下这么几种⋯⋯
https://github.com/tpope/vim-pathogen
https://github.com/gmarik/vundle
https://github.com/c9s/Vimana
但是我很不喜欢那种自己建私有目录占地为王的项目，最后那个林佑安老爷的程序是perl的，因为够轻量我很早就帮他宣传过，不过当时使用很麻烦，后来就没关注了，没想到已经开发的这么完善，还有日本perl基友同好的参与⋯⋯
所以去年我写了一个程序来自动化插件的查找和升级——没错，本文是从去年穿越过来的，以上都是去年的想法⋯⋯
https://github.com/dexteryy/yy-vimscript/blob/master/pluginscaner.py
因为vim脚本并不算很成熟的软件分发机制，.vim目录也不是很靠谱的组织结构，我不想把它们搞成一个黑箱，这个python脚本只是替代了一部分人工行为：先看看我装了哪些插件 -> 访问vim.org，搜索插件名称 -> 在插件主页下方的下载列表里找到最新版本 -> 对比版本号或日期⋯⋯
初次执行是这个样子：

结果是这个样子：

不要被那些0吓到，这显然是因为没初始化索引⋯⋯我懒得做初始化选项⋯⋯
在命令后面加上用单个插件名称，就会提示下载方式：

不管你答yes还是no，这个插件都算作升级过了⋯⋯
逐个这么执行一遍⋯⋯今后就能正常的用它检查版本更新了⋯⋯
好罢我发这篇文章是希望有人能继续完善这个脚本命令，或许有人像我一样有控制欲，只愿意接受这种自动检查和辅助安装的包管理方式。我懒得写后续的功能了，所以把它搁了一年⋯⋯
如果你要修改代码，记得把里面的google api key换掉⋯⋯
]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.limboy.com/wp-content/uploads/2009/06/picture-4.png"><img src="http://www.limboy.com/wp-content/uploads/2009/06/picture-4.png" style="width:175px;float:left;margin:0 10px 10px 0;" /></a>众所周知vim缺少官方的包管理机制，刚开始接触vim的人往往都有IDE情结，喜欢四处搜罗插件，光是ftplugin目录就要塞进十几个脚本，把“编辑器之神”武装得包罗万象无所不能，然而这些卑微的凡人，尽管手握神器，总归还是要身陷在繁忙的日常coding中，最初的欣喜和热情也在日复一日中消散，由于没有定期更新这些脚本文件的办法，更没有精力去逐个关注，渐渐就忘记了兼容性升级，忘记了:com，忘记了键位映射，忘记了操作符，最后可能连插件名字和功能都记不得了⋯⋯</p>
<p>好罢这不是那种“我有一个朋友”式的故事，我只是想说一个自动化的插件管理程序能解决这种维护烦恼，起码不至于等到世界变了OS都升级了出现严重兼容性问题了编辑器都启动不了之后再去排查原因移除长久不用的插件⋯⋯<span id="more-454"></span></p>
<p><a href="http://book.douban.com/subject/4778063/" target="_blank">这本书</a>告诉我们技术不是孤立发展的，当你察觉到一种需求的时候，意味着大半个开发者社区都有了这种需求，当你被逼得动手尝试idea，意味着同类项目已经更新了一个大版本，所以说当前比较完善的vim包管理工具大概有以下这么几种⋯⋯</p>
<p><a href="https://github.com/tpope/vim-pathogen" target="_blank">https://github.com/tpope/vim-pathogen</a><br />
<a href="https://github.com/gmarik/vundle" target="_blank">https://github.com/gmarik/vundle</a><br />
<a href="https://github.com/c9s/Vimana" target="_blank">https://github.com/c9s/Vimana</a></p>
<p>但是我很不喜欢那种自己建私有目录占地为王的项目，最后那个林佑安老爷的程序是perl的，因为够轻量我很早就帮他宣传过，不过当时使用很麻烦，后来就没关注了，没想到已经开发的这么完善，还有日本perl<del>基友</del>同好的参与⋯⋯</p>
<p>所以去年我写了一个程序来自动化插件的查找和升级——没错，本文是从去年穿越过来的，以上都是去年的想法⋯⋯</p>
<p><a href="https://github.com/dexteryy/yy-vimscript/blob/master/pluginscaner.py" target="_blank">https://github.com/dexteryy/yy-vimscript/blob/master/pluginscaner.py</a></p>
<p>因为vim脚本并不算很成熟的软件分发机制，.vim目录也不是很靠谱的组织结构，我不想把它们搞成一个黑箱，<a href="https://github.com/dexteryy/yy-vimscript/blob/master/pluginscaner.py" target="_blank">这个python脚本</a>只是替代了一部分人工行为：先看看我装了哪些插件 -> 访问vim.org，搜索插件名称 -> 在插件主页下方的下载列表里找到最新版本 -> 对比版本号或日期⋯⋯</p>
<p>初次执行是这个样子：</p>
<p><a href="http://www.limboy.com/wp-content/uploads/2011/09/p173144456-1.jpg"><img src="http://www.limboy.com/wp-content/uploads/2011/09/p173144456-1.jpg" alt="" title="p173144456-1" width="317" height="676" class="alignnone size-full wp-image-455" /></a></p>
<p>结果是这个样子：</p>
<p><a href="http://www.limboy.com/wp-content/uploads/2011/09/p173144456-2.jpg"><img src="http://www.limboy.com/wp-content/uploads/2011/09/p173144456-2.jpg" alt="" title="p173144456-2" width="350" height="563" class="alignnone size-full wp-image-456" /></a></p>
<p>不要被那些0吓到，这显然是因为没初始化索引⋯⋯我懒得做初始化选项⋯⋯</p>
<p>在命令后面加上用单个插件名称，就会提示下载方式：</p>
<p><a href="http://www.limboy.com/wp-content/uploads/2011/09/p173144456-3.jpg" target="_blank"><img src="http://www.limboy.com/wp-content/uploads/2011/09/p173144456-3.jpg" alt="" title="p173144456-3" style="width:400px" class="alignnone size-full wp-image-457" /></a></p>
<p>不管你答yes还是no，这个插件都算作升级过了⋯⋯</p>
<p>逐个这么执行一遍⋯⋯今后就能正常的用它检查版本更新了⋯⋯</p>
<p>好罢我发这篇文章是希望有人能继续完善这个脚本命令，或许有人像我一样有控制欲，只愿意接受这种自动检查和辅助安装的包管理方式。我懒得写后续的功能了，所以把它搁了一年⋯⋯</p>
<p>如果你要修改代码，记得把里面的google api key换掉⋯⋯</p>
]]></content:encoded>
			<wfw:commentRss>http://www.limboy.com/2011/09/25/vim-plugin-scaner/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>《新版阿尔法城背后的前端MVC实践》的幻灯片和⋯⋯这次没剧本⋯⋯</title>
		<link>http://www.limboy.com/2011/07/10/mvc-behind-alphatown/</link>
		<comments>http://www.limboy.com/2011/07/10/mvc-behind-alphatown/#comments</comments>
		<pubDate>Sun, 10 Jul 2011 03:16:25 +0000</pubDate>
		<dc:creator>Dexter.Yy</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[web服务/应用]]></category>
		<category><![CDATA[代码]]></category>
		<category><![CDATA[豆瓣]]></category>

		<guid isPermaLink="false">http://www.limboy.com/?p=441</guid>
		<description><![CDATA[拖到最后一天才开始准备，所以没时间写剧本照着念了T___T
幻灯片上的吐槽跟实际的讲话其实是属于两个平行世界：
http://www.slideshare.net/dexter_yy/mvc-8554206
 新版阿尔法城背后的前端MVC实践 
 View more presentations from Dexter Yy 

精选几张梗：





]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.limboy.com/wp-content/uploads/2010/12/0ee4f2b61c1d5d96b31343480a1110bf-bpfull.jpg" alt="" title="key" width="150" height="150" style="float:left;margin:0 5px 5px 0;"  />拖到最后一天才开始准备，所以没时间写剧本照着念了T___T</p>
<p>幻灯片上的吐槽跟实际的讲话其实是属于两个平行世界：<span id="more-441"></span></p>
<p><a href="http://www.slideshare.net/dexter_yy/mvc-8554206">http://www.slideshare.net/dexter_yy/mvc-8554206</a></p>
<div style="width:425px" id="__ss_8554206"> <strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/dexter_yy/mvc-8554206" title="新版阿尔法城背后的前端MVC实践" target="_blank">新版阿尔法城背后的前端MVC实践</a></strong> <iframe src="http://www.slideshare.net/slideshow/embed_code/8554206" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe>
<div style="padding:5px 0 12px"> View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> from <a href="http://www.slideshare.net/dexter_yy" target="_blank">Dexter Yy</a> </div>
</p></div>
<p>精选几张梗：</p>
<p><a href="http://www.limboy.com/wp-content/uploads/2011/07/mvc-behind-alphatown.jpeg"><img src="http://www.limboy.com/wp-content/uploads/2011/07/mvc-behind-alphatown-1024x767.jpg" alt="" title="mvc-behind-alphatown" style="width:500px" class="alignnone size-large wp-image-442" /></a></p>
<p><a href="http://www.limboy.com/wp-content/uploads/2011/07/mvc-behind-alphatown-copy-2.jpeg"><img src="http://www.limboy.com/wp-content/uploads/2011/07/mvc-behind-alphatown-copy-2-1024x767.jpg" alt="" title="mvc-behind-alphatown copy 2" style="width:500px"  class="alignnone size-large wp-image-443" /></a></p>
<p><a href="http://www.limboy.com/wp-content/uploads/2011/07/mvc-behind-alphatown-copy-3.jpeg"><img src="http://www.limboy.com/wp-content/uploads/2011/07/mvc-behind-alphatown-copy-3-1024x767.jpg" alt="" title="mvc-behind-alphatown copy 3" style="width:500px" class="alignnone size-large wp-image-444" /></a></p>
<p><a href="http://www.limboy.com/wp-content/uploads/2011/07/mvc-behind-alphatown-copy-4.jpeg"><img src="http://www.limboy.com/wp-content/uploads/2011/07/mvc-behind-alphatown-copy-4-1024x767.jpg" alt="" title="mvc-behind-alphatown copy 4" style="width:500px" class="alignnone size-large wp-image-445" /></a></p>
<p><a href="http://www.limboy.com/wp-content/uploads/2011/07/mvc-behind-alphatown-copy-5.jpeg"><img src="http://www.limboy.com/wp-content/uploads/2011/07/mvc-behind-alphatown-copy-5-1024x767.jpg" alt="" title="mvc-behind-alphatown copy 5"  style="width:500px"  class="alignnone size-large wp-image-446" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.limboy.com/2011/07/10/mvc-behind-alphatown/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>《编程人生》的读书笔记：Brendan Eich章节里关于JS语言改进的内容</title>
		<link>http://www.limboy.com/2011/04/23/brendan-eich-in-codersatwork/</link>
		<comments>http://www.limboy.com/2011/04/23/brendan-eich-in-codersatwork/#comments</comments>
		<pubDate>Sat, 23 Apr 2011 09:23:38 +0000</pubDate>
		<dc:creator>Dexter.Yy</dc:creator>
				<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://www.limboy.com/?p=383</guid>
		<description><![CDATA[这篇是之前发在豆瓣读书笔记里的内容。其他更零碎的东西就不搬运过来了，平时都发在google reader note和豆瓣日记/推荐里~
JavaScript用户的斯德哥尔摩综合症：微软不想改进，所以这语言也就这样了，用lambda代码来实现所有东西是一个优势，干嘛还要更好的语法
&#8220;Oh, it only does what it does because Microsoft stopped letting it improve, so why should we want better syntax; it’s actually a virtue to go lambda-code everything.&#8221;
Eich认为现在是程序语言发展的第二个黄金时代，应该重视语言本身的改进，不能止步不前，由于web重视兼容性，所以JS止步的太久，但不能以此为借口拒绝改进。
关于为什么要改进
跟Doug Crockford相反，Eich认为JS不能过于精简化、子集化，不能只保持de-sugar之后的几个原始特性（比如lambda），因为:
&#8220;It’s very reductionistic and it’s not for everybody.&#8221;
 &#8220;Subsetting is powerful. But to say everyone has to program in this sort of minuscule subset, that’s [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.limboy.com/wp-content/uploads/2011/04/codersatwork.jpg"><img src="http://www.limboy.com/wp-content/uploads/2011/04/codersatwork-200x300.jpg" width="200" height="300" class="alignnone size-medium wp-image-389" style="float:left;margin:0 15px 10px 0;" /></a><em>这篇是之前发在<a href="http://book.douban.com/people/Dexter_Yy/annotation/5355285/">豆瓣读书笔记</a>里的内容。其他<a href="http://www.douban.com/note/147067689/">更零碎的东西</a>就不搬运过来了，平时都发在google reader note和豆瓣日记/推荐里~</em></p>
<p>JavaScript用户的斯德哥尔摩综合症：微软不想改进，所以这语言也就这样了，用lambda代码来实现所有东西是一个优势，干嘛还要更好的语法</p>
<blockquote><p>&#8220;Oh, it only does what it does because Microsoft stopped letting it improve, so why should we want better syntax; it’s actually a virtue to go lambda-code everything.&#8221;</p></blockquote>
<p>Eich认为现在是程序语言发展的第二个黄金时代，应该重视语言本身的改进，不能止步不前，由于web重视兼容性，所以JS止步的太久，但不能以此为借口拒绝改进。</p>
<h2>关于为什么要改进</h2>
<p>跟Doug Crockford相反，Eich认为JS不能过于精简化、子集化，不能只保持de-sugar之后的几个原始特性（比如lambda），因为:<span id="more-383"></span></p>
<blockquote><p>&#8220;It’s very reductionistic and it’s not for everybody.&#8221;</p></blockquote>
<blockquote><p> &#8220;Subsetting is powerful. But to say everyone has to program in this sort of minuscule subset, that’s not usable.&#8221;</p></blockquote>
<blockquote><p>&#8220;tries to make everybody into an expert and it will not work on the large number of programmers out there who have been mistrained in these Java schools.&#8221;</p></blockquote>
<p>当初不把JS设计成一个纯粹的lambda x86语言的理由也是一样：不是每个人都想成为superhacker，程序员中也有一个金字塔。</p>
<p>lambda是JS的理论优势，但Eich认为要让JS兼具理论和实用的优势，就不能仅仅为了纯洁性而放弃好用的功能。</p>
<p>Doug等人传播了一些模式去解决JS的问题，某种程度上来说很成功，让普通开发者们在patterny level上了解到很多函数式编程的概念和惯用法，但Eich更同意Peter Norvig的观点：模式反映出程序语言本身存在某种缺陷。这些模式不是免费的午餐。</p>
<p>另一个改进的理由是，尽管程序员们可以通过写抽象库，自己解决很多问题（而且Eich非常欣赏一些JS库，认为它们令人振奋，反映了人们是何等聪明，能用非常小的工具集做出非常合理非常方便的抽象），但这种抽象能力在现有的语言中还是受到了很大限制，所以语言本身需要扩展。</p>
<h2>关于如何作改进</h2>
<p>除了Eich的blog连发的三篇文章里提到过的重大改进（比如proxy和for-in语法），这篇采访里还反映出他本来早就想引入macro，因为担心这个过程耗时很长研究性质很强，没办法吸引到微软，所以暂时搁置了，但他们一直在确保现有的和即将加入的语法糖能随时转化成宏:</p>
<blockquote><p>&#8220;we do make sure we can recast all of the sugar as macros when we have macros.&#8221;</p></blockquote>
<p>当Seibel询问对Knuth的文学化编程（literate programming）的看法时，Eich提到他对于doc comments和doc strings的兴趣，认为缺乏自动从注释里提取信息转化成可读文字和自动检查的手段，literate programming包含了整合测试和注释的含义。他们曾在ES4里做过尝试（AS3的metadata算么）：</p>
<blockquote><p>&#8220;We tried to add doc comments of some sort to ES4 with first-class metadata hooks or reflection hooks and it was just impossible to get everybody to agree.&#8221;</p></blockquote>
<p>此外Eich对静态语法分析有极大的兴趣（他的blog里也有相关的文章），他提到这是他们希望JS具备可选类型的原因之一：</p>
<blockquote><p>
&#8220;That was one of the reasons why in JavaScript we were interested in optional typing and we still are, though it’s controversial in the committee. There’s still a strong chance we’ll get some kind of hybrid type system into a future version of JavaScript.&#8221;</p></blockquote>
<p>嗯嗯其实我想说的是……以上三点（宏、文档注释、静态分析）正好都包含在我去年开发的JS预处理器的愿景之中呀~木哈哈哈哈，所见略同所见略同~</p>
<p>好罢这其实是111页的前后几页的笔记……不过都是同一个话题……</p>
<p>P.S. 学到一个新的骂人话：Java是一种“blue-collar language”（中文版翻译成“IT民工语言”） </p>
<p>再P.S. 全篇都充斥着Eich和Doug的基情口牙~~提到Doug的次数太多了~比如：</p>
<blockquote><p>Seibel: Was the ES4 proposal your chance to show the world that, “Look, I’m a really smart guy and JavaScript is a really a good language”? </p></blockquote>
<blockquote><p>Eich: No, I don’t think so. I know Doug may think that. I don’t think Doug knows me that well, but the thing is, I’m not really looking for respect, especially from the Java-heads or the trailing edge.</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.limboy.com/2011/04/23/brendan-eich-in-codersatwork/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>《通用JS时代的模块机制和编译工具》的幻灯片和……剧本……</title>
		<link>http://www.limboy.com/2010/12/19/module-and-compiler-for-common-js/</link>
		<comments>http://www.limboy.com/2010/12/19/module-and-compiler-for-common-js/#comments</comments>
		<pubDate>Sat, 18 Dec 2010 18:53:24 +0000</pubDate>
		<dc:creator>Dexter.Yy</dc:creator>
				<category><![CDATA[代码]]></category>

		<guid isPermaLink="false">http://www.limboy.com/?p=356</guid>
		<description><![CDATA[昨天在D2前端技术论坛上的演讲居然很顺利，因为是第一次演讲，我本来是完全没信心的，一个月前头脑发热答应了这件事，但是拖到最后三天才开始准备，演讲前一天只睡了4个小时，因为睡觉前刚赶出幻灯片的最后一个章节，比这些更可怕的是，本来我想逃避“口头表达”，希望演讲就是用slide说话、演示几个DEMO、把控制台和编辑器投影到大屏幕上秀给人们看……所以我在倒数第二天的时候通宵做幻灯片，图文并茂五颜六色各种效果全用上（现学mac上的keynote），没睡觉，白天在公司里试讲，只面对五六个人，却一个字都说不出来，不知道怎么即兴讲解幻灯片（特别是代码片段），连直接读幻灯片上的文字都做不到……当时便有一种必死无疑引颈就戮人生终点就在后天的感觉。
因此我做出一个艰难的决定——把演讲变成念台词，不但要准备slide，还要准备完整的讲稿，每一页slide时要说什么，有没有很难发音的词汇，什么时候停顿，点几下鼠标，都先做好万全的计划。最后一天全在忙这个，还测试了如何把ipad藏在讲台上念稿，好像找回了当年高数考试前天晚上策划作弊的亢奋感觉。
结果昨天上台时一切顺利，80页的slide刚好在50分钟左右讲完，最后一个章节没有来得及准备讲稿，却即兴的讲了很多，最后QA环节回答问题时甚至说得不想停下……现在想想，那天试讲主要的问题其实是没睡觉，缺水，颅内温度很高，大脑某些部分罢工了……
当然也有遗憾，不是会场比较小（人多了不知道会不会紧张），而是我在slide里准备的笑点……比如绝望先生的配图……没有产生任何效果。感觉演讲这种事情如果要产生最大的效果，还是更依赖情感交流，而不是内容交流……
另外我回家之后发现标题是败笔，很多人可能会把“CommonJS时代的模块和工具”理解成“CommonJS的模块和工具”，以为我要讲CommonJS……这可是前端论坛啊，其实直接叫“通用JS时代的模块和工具”就行了……
以下是今天分享的主题的slide和……龌龊的剧本（原封不动的草稿）……这样真好，连视频都不用等了，不过剧本缺最后关于工具的那个章节。另外虽然我写了这么多关于演讲的感想，但我还是希望这篇blog的反馈是关于JS模块和编译工具的……
PS: OzJS这个名字来自绿野仙踪的奥兹国，迪斯尼正在拍“The Great And Powerful Oz”……
通用JS时代的模块机制和编译工具
View more presentations from Dexter Yy.

1
大家好，今天我要分享的主题是，CommonJS时代的模块机制和编译工具
其实最早我发给小马的主题，是叫做“后浏览器时代的JavaScript——通用模块和辅助构建”
不过后来担心那个标题有点晦涩可能引起误解，
以为是讲软件工程啊流程啊方面的东西……所以就改成现在这样
不过还是有点长有点复杂，不知道大家看到这个标题会怎么想的
2
嗯可能有些人是这么想的……（点）(回头看PPT)
3
嗯不过接下来就会产生疑问……
（点）（回头看观众，停顿）
我想问现场一个问题，有多少了解，或者听说过CommonJS?
4
除了这个问题（点）
可能还会有人对时代这个词感觉比较奇怪
5
最后可能有人要问，（点）为什么要讨论模块和工具，
因为这个不像前端性能啊什么的，是大家都关心的热点
所以我觉得今天这个主题有必要先来作一下回顾
6
先来看看前端日常工作中存在的问题
（点）……这是一张以前在土豆办公室拍的照片，
中间是我，友下角有上上次D2做分享的李戎同学
这张照片看上去蛮河蟹的，其实这些人不是在做前端日常工作，而是在上班时间打游戏
7
先来回顾一下现状
（点）嗯，因为我比较紧张，可能口头表达的不太清楚，请大家直接看幻灯片上的文字
比如拿土豆网来举例，土豆从06年开始，做了一些比较之后开始使用jQuery
而到了07年，我们开始逐步积累自己的代码库
我们并没有逐步替换jQuery，但是也没有采用jQuery的结构和扩展方式去构建代码库
实际上就是把jQuery当作JS的一种内部DSL来用，DSL就是领域语言的意思
到现在也封装出了很多东西，比如常用的编程模式，web应用的模式，工具库，UI组件，等等
平时也注意把需求尽可能的抽象，让代码尽可能的可以复用，也就是不开发重复的东西
（点）这个好像是去年做的一张代码库的结构图，
现在已经过时了，不过可以看到代码单元还是蛮多的
8
9
接下来我们看一下这种现状带来的问题
（点）因为虽然有很多流行的库和框架，但是并没有真正的主流
于是不同的公司、不同的团队、不同的项目，
就可能会有各自不同的代码组织结构，不同的接口风格
这样积累下的代码就有很强的依赖性，
只能在特定项目、特定的公司里使用，或者只能在特定的团队里得到复用
就是说虽然我们重视代码复用，但是事与愿违，代码经常难以在不同项目不同团队之间迁移
难以在不同项目不同团队之间得到管理维护
如果有了独创性的东西，也很难分享到外部，很难得到广泛传播
最后的结果就是大家都在闭门造车轮。
10
来看看第二个现状（点）
比如土豆的前端代码在上线前要经过好几个环境
有开发环境，测试环境，还有跟线上数据完全一致的测试环境
最后这个测试环境中使用的静态文件（比如JS，CSS）都跟线上一样是来自CDN的，
修改后在CDN中同步要等10几分钟，在页面里生效又要等几分钟
每次做了修改，就算是简单的bugfix，也要经历很多环节才能发布上线
（点）这是土豆网首页HTML底部的截图
可以看到上面的红圈是系统自动生成的静态文件版本号，用来控制浏览器缓存
下面这行注释后面的代码是从UI文件服务器上自动抓取嵌入到页面里的
这个首页本身也是静态化的
11
这些流程也带来一些问题(点)
我一直很反对的是，在改进过程的时候损害开发者的利益
如果过程改进增加了开发成本，不应该觉得是理所当然的
而是说明有某些地方没做好，或者缺少了某些东西，比如工具
好的过程应该能隐藏复杂性，减少出错机会。
同时这些环节也对代码的管理提出更高要求，
比如有些代码需要独立的测试，每次修改也要缩小影响范围，
很多东西都依赖代码单元和文件的粒度。
12
第三个现状
这个应该不用解释，上周我刚参加过北京的velocity性能大会
可以看到现在大家对前端性能都是很重视的。
13
这里存在的问题是跟上一条相关的，
比如最简单的例子，为了方便代码的调试维护，我们会希望把JS文件拆分的很细
比如一个UI插件，希望它是独立的文件。
但是性能优化又要求减少页面里的文件请求数
为了尽可能利用浏览器缓存，可能还需要多个页面共享同一个大文件
这两方面的希望是互相矛盾的
14
刚才回顾了三个方面
他们都对同一个问题提出了要求
（点）就是JS代码本身的组织管理和使用
15
解决的途径之一，就是标题里提到的两个东西
16
这个标题可以拆成三部分
后两个是手段，第一个是背景，先来看一下这个背景
17
在这里我把CommonJS翻译成通用JS，接下来就可以看到为什么要叫通用
18
CommonJS是目前广泛流行的一套API规格
不叫它标准是因为它并不是来自像W3C,ECMA这样的官方组织
而是业界自发组织起来，发展出的项目，而且也正在在逐步成为一个事实标准
事实标准这个词是来自拉丁文的修辞，
意思是法律没有规定，但是“在事实上”或者“执行上”是怎样做
（点）它的反义词则是指有明确的法律，但是人门在现实中不会遵守
说到这两个词我们可以很容易的联想到HTML5和XHTML2，一个典型例子
这个民间项目关注的是更广义的JS开发，不止是浏览器
它的目标是建设一个JS的生态系统
19
有人可能会说现在的JS难道没有生态系统么
但是既然业界有这个目标，就说明即使有生态系统，也存在一些问题
当然其中一个问题是JS缺少服务器端开发需要的API，不过这个不是今天的重点
（点）python,ruby跟JS一样是动态语言，也非常流行，他们有内置的标准库
特别是python，有一个著名的宣传口号是“内置电池”，因为标准库非常全面
除了标准库，他们还有一个更庞大的由社区建立的代码库，其中CPAN是最早最有名的
很多人就是因为这个CPAN的存在，才会选择这个语言或者无法摆脱这个语言
JS我们知道也有大量的开源代码，但对你来说并不是每个代码都能用
比如有的是JQUERY插件，有的是YUI插件
还有一些独立的库即使很小，也必须包含重复的功能，因为它不能依赖其他东西
另外那些在浏览器里运行的代码拿到服务器端当然就更没法用了
20
比如这个例子，是我用Python写的翻墙工具，代码的第一行就是在导入标准库
包括操作系统相关，文件读写，正则表达式
下面几行我又使用了几个第三方代码库，其中的mako是一个HTML模板引擎
要获取这个库，我只需要使用Python的包管理工具
一个命令就能查找、下载、安装它自身和它依赖的其他库，而且都是最新版本
这些东西对开发带来了很大的便利，大幅提高开发效率。
21
回到CommonJS, 最早是在09年初，这个叫kevin的人建立了讨论组，最早其实是叫ServerJS讨论组
他当时写了一篇文章叫《服务器端JS需要什么》，所以最初的推动力是来自服务器端开发的需求
因为如果只局限在浏览器的特殊文化里，不接触其他语言，很多问题和需求可能都察觉不到
这个人是Mozilla的开发者工具团队的工程师，这个团队的创建和它发起的项目都很有名的
比如skywriter可能有人听说过，是一个用JS开发的在线版本编辑器
他好像是turbogears项目的创始人，turbogears是一个python的web开发框架
国外著名的开源项目网站sourceforge的新版就是用它开发的
22
Commonjs本身不提供任何具体实现，它只是约定一套东西，由兼容它的项目去实现，
按照这种约定开发出来的JS应用和模块，不做修改就可以在这些兼容COMMONJS的平台上运行
而我们最需要关注的是它对于模块的约定，后面会介绍具体的代码怎么写
23
接下来看一下广义的通用JS
其实我是借用这个词来概括当前的趋势和背景
它包含两层意思，一方面是在更多领域更多环境里需要使用JS，就是说JS本身通用了
另一方面，JS代码也需要变得通用。
24
我们来看几个例子
25
首先最自然的延伸，浏览器扩展
firefox是最早用JS开发扩展的浏览器，因为实际上它浏览器本身的界面也大量使用JS
但是以前的firefox扩展开发门槛还是很高的，比如要学习XUL，要使用C++的API
现在新的jetpack SDK不但提供了高层的JS API和测试工具，打包工具
还提供了兼容CommonJS的模块机制，让扩展开发轻松了很多
26
比如这是我以前用jetpack SDK的早期版本开发的工具软件，可以算一种自动化测试工具
简单概括就是一个爬虫，提供一个网址入口，它可以顺着超链接一路爬下去
找出所有相连的网页，并且对每一个网页应用你自定义的脚本，最后输出脚本结果的报表
因为这个不是主题而且有时间关系就不演示了
来看看它的代码，其中有一部分界面相关的JS还是以前firefox扩展的写法
不用解释就能看出代码很丑陋吧
这个是新的写法，比刚才清晰多了，可以看到我导入了几个API，每个API都是一个模块
request模块就是AJAX，pageworker相当于iframe，还导入了我自己的库TUI
27
除了firefox，其他浏览器也都开始支持用JS开发扩展，目前最火的当然是google的chrome
我这里给出一个safari扩展的例子，因为还没时间移植到chrome上
这个扩展完全用JS,HTML5和CSS3开发，只用到一张图片，UI和动画效果都是CSS3实现的
开发的时候非常方便，不过也有不爽的地方
就是它的JS没有模块化设计，apple提供的API很少，还做了很多麻烦的限制
其实我一直觉得chrome的扩展开发虽然比firefox简单，但是很难开发很强大很给力的应用
28
再来跳出浏览器，看看移动平台上的例子
(点)比如nokia目前基于厚望的QT Quick，QT本来是一个C++的GUI库
因为这一点有很多不喜欢C++的人不愿意用它，为了讨好开发者
QT quick包含QML，可以用JS和类似JS的声明式语言来快速开发手机或平板电脑上的应用
29
当然更有名的是webOS，应该多数人都听说过了
这个移动操作系统一开始就要求所有软件都用JS开发
新的2.0系统更进一步集成了nodejs，后面会做介绍，它也是CommonJS的兼容实现
也就是说我刚才给firefox扩展开发的JS模块可以直接拿到这里使用
30
除了新的移动平台，电脑桌面上其实也有很多GUI库使用了JS
这里举一个比较新的国产的例子，是豆瓣的洪强宁开发的
这里的ONERING是指魔戒里的一枚戒指统御众戒
所以这个名字意思应该是说同一种JS技术可以开发多种界面
不但能开发web上的，也可以开发桌面上的
我给他提过一个建议, 最好能兼容COMMONJS
31
下一个例子是今年欧洲JS大会上一个演示，这个演示的幻灯片里包含几个饼图
黄色是客户端，蓝色是服务器，紫色是嵌入式
可以看到09年第一届JS大会上的分享100%是关于客户端开发的
到了下一届有1/5是关于JS在服务器的应用，再一下届变成一半比例
到了这一届甚至出现了嵌入式开发，作者希望到下一届能各占1/3
32
实际上这10%的嵌入式内容是指作者自己的分享
他们希望能用JS控制一种在国外非常流行的开源硬件平台
33
这个视频演示了他们使用nodejs开发server，
然后在ipad上通过web界面里的JS代码遥控硬件设备
因为时间关系不在这里播放了……
34
最后的例子当然是服务器端的JS了
目前的绝对主流就是nodejs
传统的服务器端JS都会让人觉得很不靠谱，跟ASP之类的东西差不多。
nodejs的靠谱之处在于它的出发点不是为了在服务器和浏览器用同一种语言做开发
这种需求只是一种个人喜好，不一定是最好的选择，也不一定有实用价值。
nodejs想要推广的是基于事件的异步编程
这种编程模式对我们前端开发者来说好像是天经地义的
因为我们已经习惯了浏览器里的各种DOM事件和匿名的回调函数，
AJAX请求，图片加载，也都是异步的
但是对服务器上的开发者来说这是一种需要额外支持，需要努力去适应的模式
JS天生就提供这种支持，而这种编程模式的好处
就是可以适应大规模并发和实时性非常高的服务器应用
比如像webQQ这样的东西。
第三条里提到的erlang (erlan) 是以并发性能著称的函数式编程语言
Nodejs被拿来跟它比较，就算比不过，也说明Nodejs性能有竞争力
35
具体的例子因为时间关系就算了，重点是想强调一下它的模块数量
/*
这里如果是乔布斯演讲，幻灯片上应该会掉下一个很大的550
*/
github的一个wiki页面上收录了很多Nodejs的第三方模块
我随便抓取了一下数量，有550个以上，涉及各种功能。
对于一个发布刚好一年的项目来说这应该算蛮惊人的。
36
回头来看浏览器上的JS，跟刚才的一对比就会感觉通用的模块太少
这里说的通用还仅仅只是在前端，在不同项目不同团队不同公司之间通用
前端的JS社区很分散，jquery有jquery的社区，YUI有YUI的
虽然有一些互相借鉴但是还是有很多东西只在内部传播和使用
外部的开发者是不了解的，也不会去用
而且缺少有利于分享的基础设施，这里说的基础设施不是指开源网站
当然那个也算，这里要说的是更底层的设施
37
其中之一就是模块机制，也就是这次分享的第三个部分
38
先放大视野，看一下其他语言里的模块是什么样子
（点）先请出刚才提到过的python, python代码很简洁，相信没用过的人也看的懂
（点）这里一个框表示一个代码文件
这个文件导入了模块B，然后调用模块B里的say方法
模块B的用法就像这个文件里的一个普通对象一样
（点）模块B定义了两个变量和刚才调用过的say函数
而这个函数里又调用了一个叫cat的类，生成猫的实例，让它叫一下
但是模块B文件里并没有cat类的定义，看第一行可以知道这个类是从模块A里导入进来的
（点）模块A文件里也定义了a变量，但是因为没有声明导入它，
所以不会覆盖模块B文件里定义的a
这个就是python里模块的基本用法
从中我们可以总结几条python模块的特性
39
可以发现这些特性都符合开发者的直觉，也符合开发的需要，
对模块的开发和使用都很有好处
这里没时间演示其他语言的模块，比如ruby, actionscript3，但是这些特性都差不多的
看了这个列表, 我们还可以发现另一件事情
（点）浏览器里的JS不符合其中任何一条
40
可以对比一下：
JS存在全局作用域，不同文件会共享同一个全局命名空间（点）
所有文件一开始都会解析执行（点）
没有相关的声明语句，只能用异步加载文件的方式模拟导入的效果（点）
导入之后不管你想不想要，那个文件里的东西会全部注入到当前的命名空间里（点）
可能隐式的导入很多全局变量，覆盖或修改当前的内容（点）
为了避免这种情况，模块文件就不能采用最自然最简单的写法，比如直接定义变量和函数
而必须把所有东西都放到一个特殊的命名空间下面，比如jquery.js就是这样
JS文件自身也不包含依赖信息，如果有打包合并之类的操作
我们可能会把依赖信息写在另外的配置文件里（点）
41
我们来看看JS的代码通常是怎样组织的
（点）这个是最传统的写法，现在仍然有人在用
（点）某个网站的HTML截图，文件的顺序就是代码的依赖关系
（点）这个已经算是比较新的方法，用工具自动合并这些文件
但是如果这张图里的文件还是刚才那些文件，本质上是没有区别的，仍然依赖从上到下的顺序
42
因为这些传统，我们对浏览器端的特殊文化已经习以为常，见怪不怪了
可能没有觉得有什么不对，但是时间长了会觉得很麻烦和低效
不过最后这一条起到了一定的正面推动作用
为了改善前端性能，很多开发者开始尝试封装出一些工具
43
我把它们称作脚本加载器
44
比如这个例子，它的API提供了串行和并行加载脚本文件的功能
最大的特点应该算是用类似jquery的链式调用风格来实现串行加载
（点）（点）
45
这是另一个库，API风格有很大不同，我们看看有没有新功能
（点）（点）所以这里的并行下载，按依赖关系执行，
只是用预加载技术模拟出来的效果，实际上会请求多次
而且依赖关系仍然取决于前后顺序（点）（点）（点）
本质上还上一个库是一样的
46
最后一个例子是土豆自己的（点）(点）
JS文件名里包含在版本号是在HTML里自动生成的
（点）（点）
(点）虽然当时命名成module，本质上还是脚本加载器
47
除了大同小异的脚本加载器，我们还习惯了另一种代码组织方式
（点）这种模块模式同样也是为了克服之前列举的JS的缺陷
刚才列举的这些东西虽然有帮助，但是跟其他语言原生的模块支持相比，仍然差距很大
48
于是有人提出了更本质上的问题：JavaScript需要模块！
（点）这个名字叫戴夫赫尔曼的人并不是随便说说而已
（点）他的条件很好，跟JS创始人在一起工作，而且是TC39的成员，
TC39是负责制定下一代JS标准的小组
所以他直接发起了一个新提案，希望给JS语言加入simple module的功能
49
第二个链接是他在TC39会议上做的演讲，描述了simple module的目标和初步设计
下面这个N开头的东西是mozilla开发的实验性JS引擎，可以快速加入新功能做测试
50
简单来说他设想的simple module就是这个样子
增加了四个重要的声明语法，虽然语法很简单，但是有了这四个词之后，
JS就完全具备了跟python模块一样强大的功能
51
刚才的代码没看的明白也没关系，因为第一，它目前还只是一个稻草人提案，
就是说这个提案的功能是吸引更多人来讨论它的缺点，从而产生新的和更好的方案
第二，它是一种新引入的语法，跟CommonJS不一样，CommonJS是要用现有的语法去改善JS开发
而simple module的初衷是直接改善JS语言本身，
ES5的邮件列表里有一个相关的讨论，JS创始人布兰登也发表了意见
52
虽然短时间内不能用，但是可以先借鉴一下这个提案里列举的目标
我们是否能利用现有的JS语法和功能，来追求这些目标，实现比较理想的模块机制呢
53
之前好几次提到CommonJS的模块，现在终于轮到讨论它了
54
先请出之前展示过的爬虫程序，在介绍firefox扩展的时候，提到过它实现了CommonJS的模块
这里给出的两段代码分别来自同一个模块文件的顶部和底部（点）
圈出的部分就是CommonJS模块的主要特征（点）
55
（点）把之前python模块的示例代码，直接改成commonjs的写法（点）（点）功能特性完全一致
区别只是导入模块时不是用声明语句，而是调用require函数
可以说CommonJS满足了之前提出的所有要求，
在不引入新语法的前提下，实现了比较理想的模块机制
可惜这种代码完全没办法在浏览器里使用，障碍有两个：
第一，网页里不同JS文件之间全局命名空间是共享，而服务器端CommonJS里每个文件都是独立的
第二，require函数是阻塞式的，读取完模块文件，并返回模块对象之前，不会执行后续的代码
在服务器上这是很自然的，但是在浏览器里，读取文件是异步操作，阻塞会影响页面的交互
所以没办法、也不能让require函数阻塞代码的执行
56
于是现在要解决的问题转变成了这个了
不过在讲解决方案之前，我要先插播两页
57
58
59
嗯接下来开始介绍浏览器里的CommonJS兼容实现：RequireJS
它的开发者比我条件好，近水楼台先得月……
它定义了两个方法，require和define，其中define是关键设计，
已经成为了新的CommonJS规范，叫做异步模块
60
来看看所谓异步模块是什么样的
（点）还是跟之前Python模块和CommonJS模块的示例代码保持一致（点）（点）
可以看到require变成异步调用，第二个参数是匿名函数，
这个函数的作用域相当于模块文件的顶层作用域
作用域里的代码可以跟服务器端CommonJS完全一致，
包括使用阻塞式的require，用exports生成模块对象
这个作用域里也可以直接采用传统的模块模式的写法，用return来生成模块对象
依赖的模块会被转变成模块对象，通过函数参数传入
define函数具备require的所有功能，同时提供了定义新模块的能力，
当模块代码位于独立的文件里
比如像这里的模块A，模块名称的参数可以省略，直接绑定到文件名
61
异步模块的require和define还有一种衍生的用法，就是用来请求JSONP接口
define不但支持传入函数，也可以直接传入一个对象作为模块对象
用这个方法请求JSONP的好处是不用担心callback污染全局命名空间，
还可以起到缓存的效果，因为模块文件只会加载一次
62
总结一下异步模块的优点
63
刚才说过requireJS算是异步模块的一个官方实现，
不过相比之下我更喜欢自己实现的oz.js
一个原因是代码更少更简单，另一个原因是我对define函数的用法有不同的意见
requirejs仍然采用服务器端的做法，把模块名直接等同于文件地址，
但是前端开发中很少有这么理想的情况
而对于要下载的JS文件不需要做静态的声明，只在运行时里检查，也会产生很多不便
64
对照代码看看oz.js的def方法有什么不同
65
内部细节只强调几个功能上的问题
oz.js本身包含了前面提到的脚本加载器的所有功能，但是只会用到并行加载，
因为模块文件之间没有依赖关系。
66
在模块部分的最后引用一下这句话：“让代码更容易分享，大家就会分享更多的代码”。
]]></description>
			<content:encoded><![CDATA[<p><img src="http://www.limboy.com/wp-content/uploads/2010/12/0ee4f2b61c1d5d96b31343480a1110bf-bpfull.jpg" alt="" title="key" width="150" height="150" style="float:left;margin:0 5px 5px 0;"  />昨天在<a href="http://www.d2forum.org/d2/5/" target="_blank">D2前端技术论坛</a>上的演讲居然很顺利，因为是第一次演讲，我本来是完全没信心的，一个月前头脑发热答应了这件事，但是拖到最后三天才开始准备，演讲前一天只睡了4个小时，因为睡觉前刚赶出幻灯片的最后一个章节，比这些更可怕的是，本来我想逃避“口头表达”，希望演讲就是用slide说话、演示几个DEMO、把控制台和编辑器投影到大屏幕上秀给人们看……所以我在倒数第二天的时候通宵做幻灯片，图文并茂五颜六色各种效果全用上（现学mac上的keynote），没睡觉，白天在公司里试讲，只面对五六个人，却一个字都说不出来，不知道怎么即兴讲解幻灯片（特别是代码片段），连直接读幻灯片上的文字都做不到……当时便有一种必死无疑引颈就戮人生终点就在后天的感觉。</p>
<p>因此我做出一个艰难的决定——把演讲变成念台词，不但要准备slide，还要准备完整的讲稿，每一页slide时要说什么，有没有很难发音的词汇，什么时候停顿，点几下鼠标，都先做好万全的计划。最后一天全在忙这个，还测试了如何把ipad藏在讲台上念稿，好像找回了当年高数考试前天晚上策划作弊的亢奋感觉。<span id="more-356"></span></p>
<p>结果昨天上台时一切顺利，80页的slide刚好在50分钟左右讲完，最后一个章节没有来得及准备讲稿，却即兴的讲了很多，最后QA环节回答问题时甚至说得不想停下……现在想想，那天试讲主要的问题其实是没睡觉，缺水，颅内温度很高，大脑某些部分罢工了……</p>
<p>当然也有遗憾，不是会场比较小（人多了不知道会不会紧张），而是我在slide里准备的笑点……比如绝望先生的配图……没有产生任何效果。感觉演讲这种事情如果要产生最大的效果，还是更依赖情感交流，而不是内容交流……</p>
<p>另外我回家之后发现标题是败笔，很多人可能会把“CommonJS时代的模块和工具”理解成“CommonJS的模块和工具”，以为我要讲CommonJS……这可是前端论坛啊，其实直接叫“通用JS时代的模块和工具”就行了……</p>
<p>以下是今天分享的主题的<a href="http://www.slideshare.net/dexter_yy/js-6228773" target="_blank">slide</a>和……龌龊的剧本（原封不动的草稿）……这样真好，连视频都不用等了，不过剧本缺最后关于工具的那个章节。另外虽然我写了这么多关于演讲的感想，但我还是希望这篇blog的反馈是关于JS模块和编译工具的……</p>
<p>PS: <a href="https://github.com/dexteryy/OzJS" href="_blank">OzJS</a>这个名字来自绿野仙踪的奥兹国，迪斯尼正在拍“The Great And Powerful Oz”……</p>
<div style="width:425px" id="__ss_6228773"><strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/dexter_yy/js-6228773" title="通用JS时代的模块机制和编译工具">通用JS时代的模块机制和编译工具</a></strong><object id="__sse6228773" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=module-and-compiler-for-common-101218105758-phpapp02&#038;rel=0&#038;stripped_title=js-6228773&#038;userName=dexter_yy" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse6228773" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=module-and-compiler-for-common-101218105758-phpapp02&#038;rel=0&#038;stripped_title=js-6228773&#038;userName=dexter_yy" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object>
<div style="padding:5px 0 12px">View more <a href="http://www.slideshare.net/">presentations</a> from <a href="http://www.slideshare.net/dexter_yy">Dexter Yy</a>.</div>
</div>
<p>1<br />
大家好，今天我要分享的主题是，CommonJS时代的模块机制和编译工具<br />
其实最早我发给小马的主题，是叫做“后浏览器时代的JavaScript——通用模块和辅助构建”<br />
不过后来担心那个标题有点晦涩可能引起误解，<br />
以为是讲软件工程啊流程啊方面的东西……所以就改成现在这样<br />
不过还是有点长有点复杂，不知道大家看到这个标题会怎么想的</p>
<p>2<br />
嗯可能有些人是这么想的……（点）(回头看PPT)</p>
<p>3<br />
嗯不过接下来就会产生疑问……<br />
（点）（回头看观众，停顿）<br />
我想问现场一个问题，有多少了解，或者听说过CommonJS?</p>
<p>4<br />
除了这个问题（点）<br />
可能还会有人对时代这个词感觉比较奇怪</p>
<p>5<br />
最后可能有人要问，（点）为什么要讨论模块和工具，<br />
因为这个不像前端性能啊什么的，是大家都关心的热点<br />
所以我觉得今天这个主题有必要先来作一下回顾</p>
<p>6<br />
先来看看前端日常工作中存在的问题<br />
（点）……这是一张以前在土豆办公室拍的照片，<br />
中间是我，友下角有上上次D2做分享的李戎同学<br />
这张照片看上去蛮河蟹的，其实这些人不是在做前端日常工作，而是在上班时间打游戏</p>
<p>7<br />
先来回顾一下现状<br />
（点）嗯，因为我比较紧张，可能口头表达的不太清楚，请大家直接看幻灯片上的文字<br />
比如拿土豆网来举例，土豆从06年开始，做了一些比较之后开始使用jQuery<br />
而到了07年，我们开始逐步积累自己的代码库<br />
我们并没有逐步替换jQuery，但是也没有采用jQuery的结构和扩展方式去构建代码库<br />
实际上就是把jQuery当作JS的一种内部DSL来用，DSL就是领域语言的意思<br />
到现在也封装出了很多东西，比如常用的编程模式，web应用的模式，工具库，UI组件，等等<br />
平时也注意把需求尽可能的抽象，让代码尽可能的可以复用，也就是不开发重复的东西<br />
（点）这个好像是去年做的一张代码库的结构图，<br />
现在已经过时了，不过可以看到代码单元还是蛮多的</p>
<p>8</p>
<p>9<br />
接下来我们看一下这种现状带来的问题<br />
（点）因为虽然有很多流行的库和框架，但是并没有真正的主流<br />
于是不同的公司、不同的团队、不同的项目，<br />
就可能会有各自不同的代码组织结构，不同的接口风格<br />
这样积累下的代码就有很强的依赖性，<br />
只能在特定项目、特定的公司里使用，或者只能在特定的团队里得到复用<br />
就是说虽然我们重视代码复用，但是事与愿违，代码经常难以在不同项目不同团队之间迁移<br />
难以在不同项目不同团队之间得到管理维护<br />
如果有了独创性的东西，也很难分享到外部，很难得到广泛传播<br />
最后的结果就是大家都在闭门造车轮。</p>
<p>10<br />
来看看第二个现状（点）<br />
比如土豆的前端代码在上线前要经过好几个环境<br />
有开发环境，测试环境，还有跟线上数据完全一致的测试环境<br />
最后这个测试环境中使用的静态文件（比如JS，CSS）都跟线上一样是来自CDN的，<br />
修改后在CDN中同步要等10几分钟，在页面里生效又要等几分钟<br />
每次做了修改，就算是简单的bugfix，也要经历很多环节才能发布上线<br />
（点）这是土豆网首页HTML底部的截图<br />
可以看到上面的红圈是系统自动生成的静态文件版本号，用来控制浏览器缓存<br />
下面这行注释后面的代码是从UI文件服务器上自动抓取嵌入到页面里的<br />
这个首页本身也是静态化的</p>
<p>11<br />
这些流程也带来一些问题(点)<br />
我一直很反对的是，在改进过程的时候损害开发者的利益<br />
如果过程改进增加了开发成本，不应该觉得是理所当然的<br />
而是说明有某些地方没做好，或者缺少了某些东西，比如工具<br />
好的过程应该能隐藏复杂性，减少出错机会。<br />
同时这些环节也对代码的管理提出更高要求，<br />
比如有些代码需要独立的测试，每次修改也要缩小影响范围，<br />
很多东西都依赖代码单元和文件的粒度。</p>
<p>12<br />
第三个现状<br />
这个应该不用解释，上周我刚参加过北京的velocity性能大会<br />
可以看到现在大家对前端性能都是很重视的。</p>
<p>13<br />
这里存在的问题是跟上一条相关的，<br />
比如最简单的例子，为了方便代码的调试维护，我们会希望把JS文件拆分的很细<br />
比如一个UI插件，希望它是独立的文件。<br />
但是性能优化又要求减少页面里的文件请求数<br />
为了尽可能利用浏览器缓存，可能还需要多个页面共享同一个大文件<br />
这两方面的希望是互相矛盾的</p>
<p>14<br />
刚才回顾了三个方面<br />
他们都对同一个问题提出了要求<br />
（点）就是JS代码本身的组织管理和使用</p>
<p>15<br />
解决的途径之一，就是标题里提到的两个东西</p>
<p>16<br />
这个标题可以拆成三部分<br />
后两个是手段，第一个是背景，先来看一下这个背景</p>
<p>17<br />
在这里我把CommonJS翻译成通用JS，接下来就可以看到为什么要叫通用</p>
<p>18<br />
CommonJS是目前广泛流行的一套API规格<br />
不叫它标准是因为它并不是来自像W3C,ECMA这样的官方组织<br />
而是业界自发组织起来，发展出的项目，而且也正在在逐步成为一个事实标准<br />
事实标准这个词是来自拉丁文的修辞，<br />
意思是法律没有规定，但是“在事实上”或者“执行上”是怎样做<br />
（点）它的反义词则是指有明确的法律，但是人门在现实中不会遵守<br />
说到这两个词我们可以很容易的联想到HTML5和XHTML2，一个典型例子<br />
这个民间项目关注的是更广义的JS开发，不止是浏览器<br />
它的目标是建设一个JS的生态系统</p>
<p>19<br />
有人可能会说现在的JS难道没有生态系统么<br />
但是既然业界有这个目标，就说明即使有生态系统，也存在一些问题<br />
当然其中一个问题是JS缺少服务器端开发需要的API，不过这个不是今天的重点<br />
（点）python,ruby跟JS一样是动态语言，也非常流行，他们有内置的标准库<br />
特别是python，有一个著名的宣传口号是“内置电池”，因为标准库非常全面<br />
除了标准库，他们还有一个更庞大的由社区建立的代码库，其中CPAN是最早最有名的<br />
很多人就是因为这个CPAN的存在，才会选择这个语言或者无法摆脱这个语言<br />
JS我们知道也有大量的开源代码，但对你来说并不是每个代码都能用<br />
比如有的是JQUERY插件，有的是YUI插件<br />
还有一些独立的库即使很小，也必须包含重复的功能，因为它不能依赖其他东西<br />
另外那些在浏览器里运行的代码拿到服务器端当然就更没法用了</p>
<p>20<br />
比如这个例子，是我用Python写的翻墙工具，代码的第一行就是在导入标准库<br />
包括操作系统相关，文件读写，正则表达式<br />
下面几行我又使用了几个第三方代码库，其中的mako是一个HTML模板引擎<br />
要获取这个库，我只需要使用Python的包管理工具<br />
一个命令就能查找、下载、安装它自身和它依赖的其他库，而且都是最新版本<br />
这些东西对开发带来了很大的便利，大幅提高开发效率。</p>
<p>21<br />
回到CommonJS, 最早是在09年初，这个叫kevin的人建立了讨论组，最早其实是叫ServerJS讨论组<br />
他当时写了一篇文章叫《服务器端JS需要什么》，所以最初的推动力是来自服务器端开发的需求<br />
因为如果只局限在浏览器的特殊文化里，不接触其他语言，很多问题和需求可能都察觉不到<br />
这个人是Mozilla的开发者工具团队的工程师，这个团队的创建和它发起的项目都很有名的<br />
比如skywriter可能有人听说过，是一个用JS开发的在线版本编辑器<br />
他好像是turbogears项目的创始人，turbogears是一个python的web开发框架<br />
国外著名的开源项目网站sourceforge的新版就是用它开发的</p>
<p>22<br />
Commonjs本身不提供任何具体实现，它只是约定一套东西，由兼容它的项目去实现，<br />
按照这种约定开发出来的JS应用和模块，不做修改就可以在这些兼容COMMONJS的平台上运行<br />
而我们最需要关注的是它对于模块的约定，后面会介绍具体的代码怎么写</p>
<p>23<br />
接下来看一下广义的通用JS<br />
其实我是借用这个词来概括当前的趋势和背景<br />
它包含两层意思，一方面是在更多领域更多环境里需要使用JS，就是说JS本身通用了<br />
另一方面，JS代码也需要变得通用。</p>
<p>24<br />
我们来看几个例子</p>
<p>25<br />
首先最自然的延伸，浏览器扩展<br />
firefox是最早用JS开发扩展的浏览器，因为实际上它浏览器本身的界面也大量使用JS<br />
但是以前的firefox扩展开发门槛还是很高的，比如要学习XUL，要使用C++的API<br />
现在新的jetpack SDK不但提供了高层的JS API和测试工具，打包工具<br />
还提供了兼容CommonJS的模块机制，让扩展开发轻松了很多</p>
<p>26<br />
比如这是我以前用jetpack SDK的早期版本开发的工具软件，可以算一种自动化测试工具<br />
简单概括就是一个爬虫，提供一个网址入口，它可以顺着超链接一路爬下去<br />
找出所有相连的网页，并且对每一个网页应用你自定义的脚本，最后输出脚本结果的报表<br />
因为这个不是主题而且有时间关系就不演示了<br />
来看看它的代码，其中有一部分界面相关的JS还是以前firefox扩展的写法<br />
不用解释就能看出代码很丑陋吧<br />
这个是新的写法，比刚才清晰多了，可以看到我导入了几个API，每个API都是一个模块<br />
request模块就是AJAX，pageworker相当于iframe，还导入了我自己的库TUI</p>
<p>27<br />
除了firefox，其他浏览器也都开始支持用JS开发扩展，目前最火的当然是google的chrome<br />
我这里给出一个safari扩展的例子，因为还没时间移植到chrome上<br />
这个扩展完全用JS,HTML5和CSS3开发，只用到一张图片，UI和动画效果都是CSS3实现的<br />
开发的时候非常方便，不过也有不爽的地方<br />
就是它的JS没有模块化设计，apple提供的API很少，还做了很多麻烦的限制<br />
其实我一直觉得chrome的扩展开发虽然比firefox简单，但是很难开发很强大很给力的应用</p>
<p>28<br />
再来跳出浏览器，看看移动平台上的例子<br />
(点)比如nokia目前基于厚望的QT Quick，QT本来是一个C++的GUI库<br />
因为这一点有很多不喜欢C++的人不愿意用它，为了讨好开发者<br />
QT quick包含QML，可以用JS和类似JS的声明式语言来快速开发手机或平板电脑上的应用</p>
<p>29<br />
当然更有名的是webOS，应该多数人都听说过了<br />
这个移动操作系统一开始就要求所有软件都用JS开发<br />
新的2.0系统更进一步集成了nodejs，后面会做介绍，它也是CommonJS的兼容实现<br />
也就是说我刚才给firefox扩展开发的JS模块可以直接拿到这里使用</p>
<p>30<br />
除了新的移动平台，电脑桌面上其实也有很多GUI库使用了JS<br />
这里举一个比较新的国产的例子，是豆瓣的洪强宁开发的<br />
这里的ONERING是指魔戒里的一枚戒指统御众戒<br />
所以这个名字意思应该是说同一种JS技术可以开发多种界面<br />
不但能开发web上的，也可以开发桌面上的<br />
我给他提过一个建议, 最好能兼容COMMONJS</p>
<p>31<br />
下一个例子是今年欧洲JS大会上一个演示，这个演示的幻灯片里包含几个饼图<br />
黄色是客户端，蓝色是服务器，紫色是嵌入式<br />
可以看到09年第一届JS大会上的分享100%是关于客户端开发的<br />
到了下一届有1/5是关于JS在服务器的应用，再一下届变成一半比例<br />
到了这一届甚至出现了嵌入式开发，作者希望到下一届能各占1/3</p>
<p>32<br />
实际上这10%的嵌入式内容是指作者自己的分享<br />
他们希望能用JS控制一种在国外非常流行的开源硬件平台</p>
<p>33<br />
这个视频演示了他们使用nodejs开发server，<br />
然后在ipad上通过web界面里的JS代码遥控硬件设备<br />
因为时间关系不在这里播放了……</p>
<p>34<br />
最后的例子当然是服务器端的JS了<br />
目前的绝对主流就是nodejs<br />
传统的服务器端JS都会让人觉得很不靠谱，跟ASP之类的东西差不多。<br />
nodejs的靠谱之处在于它的出发点不是为了在服务器和浏览器用同一种语言做开发<br />
这种需求只是一种个人喜好，不一定是最好的选择，也不一定有实用价值。<br />
nodejs想要推广的是基于事件的异步编程<br />
这种编程模式对我们前端开发者来说好像是天经地义的<br />
因为我们已经习惯了浏览器里的各种DOM事件和匿名的回调函数，<br />
AJAX请求，图片加载，也都是异步的<br />
但是对服务器上的开发者来说这是一种需要额外支持，需要努力去适应的模式<br />
JS天生就提供这种支持，而这种编程模式的好处<br />
就是可以适应大规模并发和实时性非常高的服务器应用<br />
比如像webQQ这样的东西。<br />
第三条里提到的erlang (erlan) 是以并发性能著称的函数式编程语言<br />
Nodejs被拿来跟它比较，就算比不过，也说明Nodejs性能有竞争力</p>
<p>35<br />
具体的例子因为时间关系就算了，重点是想强调一下它的模块数量<br />
/*<br />
这里如果是乔布斯演讲，幻灯片上应该会掉下一个很大的550<br />
*/<br />
github的一个wiki页面上收录了很多Nodejs的第三方模块<br />
我随便抓取了一下数量，有550个以上，涉及各种功能。<br />
对于一个发布刚好一年的项目来说这应该算蛮惊人的。</p>
<p>36<br />
回头来看浏览器上的JS，跟刚才的一对比就会感觉通用的模块太少<br />
这里说的通用还仅仅只是在前端，在不同项目不同团队不同公司之间通用<br />
前端的JS社区很分散，jquery有jquery的社区，YUI有YUI的<br />
虽然有一些互相借鉴但是还是有很多东西只在内部传播和使用<br />
外部的开发者是不了解的，也不会去用<br />
而且缺少有利于分享的基础设施，这里说的基础设施不是指开源网站<br />
当然那个也算，这里要说的是更底层的设施</p>
<p>37<br />
其中之一就是模块机制，也就是这次分享的第三个部分</p>
<p>38<br />
先放大视野，看一下其他语言里的模块是什么样子<br />
（点）先请出刚才提到过的python, python代码很简洁，相信没用过的人也看的懂<br />
（点）这里一个框表示一个代码文件<br />
这个文件导入了模块B，然后调用模块B里的say方法<br />
模块B的用法就像这个文件里的一个普通对象一样<br />
（点）模块B定义了两个变量和刚才调用过的say函数<br />
而这个函数里又调用了一个叫cat的类，生成猫的实例，让它叫一下<br />
但是模块B文件里并没有cat类的定义，看第一行可以知道这个类是从模块A里导入进来的<br />
（点）模块A文件里也定义了a变量，但是因为没有声明导入它，<br />
所以不会覆盖模块B文件里定义的a<br />
这个就是python里模块的基本用法<br />
从中我们可以总结几条python模块的特性</p>
<p>39<br />
可以发现这些特性都符合开发者的直觉，也符合开发的需要，<br />
对模块的开发和使用都很有好处<br />
这里没时间演示其他语言的模块，比如ruby, actionscript3，但是这些特性都差不多的<br />
看了这个列表, 我们还可以发现另一件事情<br />
（点）浏览器里的JS不符合其中任何一条</p>
<p>40<br />
可以对比一下：<br />
JS存在全局作用域，不同文件会共享同一个全局命名空间（点）<br />
所有文件一开始都会解析执行（点）<br />
没有相关的声明语句，只能用异步加载文件的方式模拟导入的效果（点）<br />
导入之后不管你想不想要，那个文件里的东西会全部注入到当前的命名空间里（点）<br />
可能隐式的导入很多全局变量，覆盖或修改当前的内容（点）</p>
<p>为了避免这种情况，模块文件就不能采用最自然最简单的写法，比如直接定义变量和函数<br />
而必须把所有东西都放到一个特殊的命名空间下面，比如jquery.js就是这样</p>
<p>JS文件自身也不包含依赖信息，如果有打包合并之类的操作<br />
我们可能会把依赖信息写在另外的配置文件里（点）</p>
<p>41<br />
我们来看看JS的代码通常是怎样组织的<br />
（点）这个是最传统的写法，现在仍然有人在用<br />
（点）某个网站的HTML截图，文件的顺序就是代码的依赖关系<br />
（点）这个已经算是比较新的方法，用工具自动合并这些文件<br />
但是如果这张图里的文件还是刚才那些文件，本质上是没有区别的，仍然依赖从上到下的顺序</p>
<p>42<br />
因为这些传统，我们对浏览器端的特殊文化已经习以为常，见怪不怪了<br />
可能没有觉得有什么不对，但是时间长了会觉得很麻烦和低效<br />
不过最后这一条起到了一定的正面推动作用<br />
为了改善前端性能，很多开发者开始尝试封装出一些工具</p>
<p>43<br />
我把它们称作脚本加载器</p>
<p>44<br />
比如这个例子，它的API提供了串行和并行加载脚本文件的功能<br />
最大的特点应该算是用类似jquery的链式调用风格来实现串行加载<br />
（点）（点）</p>
<p>45<br />
这是另一个库，API风格有很大不同，我们看看有没有新功能<br />
（点）（点）所以这里的并行下载，按依赖关系执行，<br />
只是用预加载技术模拟出来的效果，实际上会请求多次<br />
而且依赖关系仍然取决于前后顺序（点）（点）（点）<br />
本质上还上一个库是一样的</p>
<p>46<br />
最后一个例子是土豆自己的（点）(点）<br />
JS文件名里包含在版本号是在HTML里自动生成的<br />
（点）（点）<br />
(点）虽然当时命名成module，本质上还是脚本加载器</p>
<p>47<br />
除了大同小异的脚本加载器，我们还习惯了另一种代码组织方式<br />
（点）这种模块模式同样也是为了克服之前列举的JS的缺陷</p>
<p>刚才列举的这些东西虽然有帮助，但是跟其他语言原生的模块支持相比，仍然差距很大</p>
<p>48<br />
于是有人提出了更本质上的问题：JavaScript需要模块！<br />
（点）这个名字叫戴夫赫尔曼的人并不是随便说说而已<br />
（点）他的条件很好，跟JS创始人在一起工作，而且是TC39的成员，<br />
TC39是负责制定下一代JS标准的小组<br />
所以他直接发起了一个新提案，希望给JS语言加入simple module的功能</p>
<p>49<br />
第二个链接是他在TC39会议上做的演讲，描述了simple module的目标和初步设计<br />
下面这个N开头的东西是mozilla开发的实验性JS引擎，可以快速加入新功能做测试</p>
<p>50<br />
简单来说他设想的simple module就是这个样子<br />
增加了四个重要的声明语法，虽然语法很简单，但是有了这四个词之后，<br />
JS就完全具备了跟python模块一样强大的功能</p>
<p>51<br />
刚才的代码没看的明白也没关系，因为第一，它目前还只是一个稻草人提案，<br />
就是说这个提案的功能是吸引更多人来讨论它的缺点，从而产生新的和更好的方案<br />
第二，它是一种新引入的语法，跟CommonJS不一样，CommonJS是要用现有的语法去改善JS开发<br />
而simple module的初衷是直接改善JS语言本身，<br />
ES5的邮件列表里有一个相关的讨论，JS创始人布兰登也发表了意见</p>
<p>52<br />
虽然短时间内不能用，但是可以先借鉴一下这个提案里列举的目标<br />
我们是否能利用现有的JS语法和功能，来追求这些目标，实现比较理想的模块机制呢</p>
<p>53<br />
之前好几次提到CommonJS的模块，现在终于轮到讨论它了</p>
<p>54<br />
先请出之前展示过的爬虫程序，在介绍firefox扩展的时候，提到过它实现了CommonJS的模块<br />
这里给出的两段代码分别来自同一个模块文件的顶部和底部（点）<br />
圈出的部分就是CommonJS模块的主要特征（点）</p>
<p>55<br />
（点）把之前python模块的示例代码，直接改成commonjs的写法（点）（点）功能特性完全一致<br />
区别只是导入模块时不是用声明语句，而是调用require函数<br />
可以说CommonJS满足了之前提出的所有要求，<br />
在不引入新语法的前提下，实现了比较理想的模块机制<br />
可惜这种代码完全没办法在浏览器里使用，障碍有两个：<br />
第一，网页里不同JS文件之间全局命名空间是共享，而服务器端CommonJS里每个文件都是独立的<br />
第二，require函数是阻塞式的，读取完模块文件，并返回模块对象之前，不会执行后续的代码<br />
在服务器上这是很自然的，但是在浏览器里，读取文件是异步操作，阻塞会影响页面的交互<br />
所以没办法、也不能让require函数阻塞代码的执行</p>
<p>56<br />
于是现在要解决的问题转变成了这个了<br />
不过在讲解决方案之前，我要先插播两页</p>
<p>57</p>
<p>58</p>
<p>59<br />
嗯接下来开始介绍浏览器里的CommonJS兼容实现：RequireJS<br />
它的开发者比我条件好，近水楼台先得月……<br />
它定义了两个方法，require和define，其中define是关键设计，<br />
已经成为了新的CommonJS规范，叫做异步模块</p>
<p>60<br />
来看看所谓异步模块是什么样的<br />
（点）还是跟之前Python模块和CommonJS模块的示例代码保持一致（点）（点）<br />
可以看到require变成异步调用，第二个参数是匿名函数，<br />
这个函数的作用域相当于模块文件的顶层作用域<br />
作用域里的代码可以跟服务器端CommonJS完全一致，<br />
包括使用阻塞式的require，用exports生成模块对象<br />
这个作用域里也可以直接采用传统的模块模式的写法，用return来生成模块对象<br />
依赖的模块会被转变成模块对象，通过函数参数传入<br />
define函数具备require的所有功能，同时提供了定义新模块的能力，<br />
当模块代码位于独立的文件里<br />
比如像这里的模块A，模块名称的参数可以省略，直接绑定到文件名</p>
<p>61<br />
异步模块的require和define还有一种衍生的用法，就是用来请求JSONP接口<br />
define不但支持传入函数，也可以直接传入一个对象作为模块对象<br />
用这个方法请求JSONP的好处是不用担心callback污染全局命名空间，<br />
还可以起到缓存的效果，因为模块文件只会加载一次</p>
<p>62<br />
总结一下异步模块的优点</p>
<p>63<br />
刚才说过requireJS算是异步模块的一个官方实现，<br />
不过相比之下我更喜欢自己实现的oz.js<br />
一个原因是代码更少更简单，另一个原因是我对define函数的用法有不同的意见<br />
requirejs仍然采用服务器端的做法，把模块名直接等同于文件地址，<br />
但是前端开发中很少有这么理想的情况<br />
而对于要下载的JS文件不需要做静态的声明，只在运行时里检查，也会产生很多不便</p>
<p>64<br />
对照代码看看oz.js的def方法有什么不同</p>
<p>65<br />
内部细节只强调几个功能上的问题<br />
oz.js本身包含了前面提到的脚本加载器的所有功能，但是只会用到并行加载，<br />
因为模块文件之间没有依赖关系。</p>
<p>66<br />
在模块部分的最后引用一下这句话：“让代码更容易分享，大家就会分享更多的代码”。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.limboy.com/2010/12/19/module-and-compiler-for-common-js/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>GrassMudMonkey: 浏览器里的草泥马程序解释器</title>
		<link>http://www.limboy.com/2010/03/21/grassmudmonkey/</link>
		<comments>http://www.limboy.com/2010/03/21/grassmudmonkey/#comments</comments>
		<pubDate>Sun, 21 Mar 2010 04:38:05 +0000</pubDate>
		<dc:creator>Dexter.Yy</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[kuso]]></category>
		<category><![CDATA[代码]]></category>

		<guid isPermaLink="false">http://www.limboy.com/2010/03/21/grassmudmonkey/</guid>
		<description><![CDATA[一款具有划时代意义的产品隆重面世！来自中国民营企业土豆网的高级资深前端总工程师瀚主程序员瀚首席前端架构师德克斯特同志（Fellow Dexter the Advanced Senior Principal Front-end Engineer &#038; Chief Programmer &#038; Lead Architect）胸怀大志，以民族振兴和国家富强为己任，充分发扬自力更生自主创新的精神，在没看过龙书没读完SCIP的简陋条件下，敢打敢拼，艰苦朴素，不吃饭不喝水不晒衣服，终于研发出了可以在浏览器中运行草泥马程序的纯JavaScript实现的草泥马引擎GrassMudMonkey，这标志着中国自主知识产权的编程语言——草泥马语（GrassMudHorse Programming Language）——在核心技术上又取得了重大突破，打破了谷歌，魔斯拉等西方国家企业在浏览器内嵌脚本技术上的垄断，为三网融合瀚大中华局域网的发展创造了良好的技术条件，回首往昔，展望未来，完全基于汉字的编程方式的普及必将推动民族凝聚，促进和谐，有效抵制西方文化入侵乃至外星使徒入侵。
草泥马语是一种轻量的，简洁的，紧凑的，图灵完备的，基于堆栈的语言，与美国瀚北欧企业开发的JägerMonkey，Nitro，V8，Carakan等浏览器内嵌引擎支持的JavaScript语言相比，草泥马语仅使用“草”，“泥”，“马”三个字符来完成一切任务，其语言设计的先进性和前瞻性，不仅被全球开发社区争相学习借鉴，应用到CPU和单片机的指令设计中，甚至还已经出现了相似度高达97%的山寨项目
学习草泥马语的最快方式是阅读官方项目组发布的草泥马语言规范及其英文翻译版
GrassMudMonkey利用JavaScript来实现词法分析和运行时，完整源代码：http://github.com/dexteryy/GrassMudMonkey/blob/master/grassmudmonkey.js
效果演示 / 在线的集成开发环境（提供控制台）：
默认示例里的程序通过循环输出1到10的整数
[单独打开]

注意事项1: 由于美学智慧上的分歧，GrassMudMonkey跟官方的JAVA版本有细微区别：不支持“河蟹”。
注意事项2：仅仅针对一两段程序做了基准测试，涵盖了大部分指令，但不排除有实现不一致的地方。
注释事项3：输入接口懒得写了，全部返回默认值，whitespace网站上的一些示例程序会因此无法运行。
]]></description>
			<content:encoded><![CDATA[<p><a href='http://www.limboy.com/wp-content/uploads/2010/03/gmh.jpg' title='gmh.jpg' target="_blank"><img src='http://www.limboy.com/wp-content/uploads/2010/03/gmh.jpg' alt='gmh.jpg' style="width:240px;float:left;margin:0 10px 10px 0;" /></a>一款具有划时代意义的产品隆重面世！来自中国民营企业土豆网的高级资深前端总工程师瀚主程序员瀚首席前端架构师德克斯特同志（Fellow Dexter the Advanced Senior Principal Front-end Engineer &#038; Chief Programmer &#038; Lead Architect）胸怀大志，以民族振兴和国家富强为己任，充分发扬自力更生自主创新的精神，在没看过龙书没读完SCIP的简陋条件下，敢打敢拼，艰苦朴素，不吃饭不喝水不晒衣服，终于研发出了可以在浏览器中运行草泥马程序的<a href="http://github.com/dexteryy/GrassMudMonkey" target="_blank">纯JavaScript实现的草泥马引擎GrassMudMonkey</a>，这标志着中国自主知识产权的编程语言——<a href="http://code.google.com/p/grass-mud-horse/" target="_blank">草泥马语（GrassMudHorse Programming Language）</a>——在核心技术上又取得了重大突破，打破了谷歌，魔斯拉等西方国家企业在浏览器内嵌脚本技术上的垄断，为三网融合瀚大中华局域网的发展创造了良好的技术条件，回首往昔，展望未来，完全基于汉字的编程方式的普及必将推动民族凝聚，促进和谐，有效抵制西方文化入侵乃至<a href="http://www.tudou.com/playlist/playindex.do?lid=8172334" target="_blank">外星使徒入侵</a>。<span id="more-255"></span></p>
<p>草泥马语是一种轻量的，简洁的，紧凑的，图灵完备的，基于堆栈的语言，与美国瀚北欧企业开发的JägerMonkey，Nitro，V8，Carakan等浏览器内嵌引擎支持的JavaScript语言相比，草泥马语仅使用“草”，“泥”，“马”三个字符来完成一切任务，其语言设计的先进性和前瞻性，不仅被全球开发社区争相学习借鉴，应用到CPU和单片机的指令设计中，甚至还已经出现了<a href="http://compsoc.dur.ac.uk/whitespace" target="_blank">相似度高达97%的山寨项目</a></p>
<p>学习草泥马语的最快方式是阅读官方项目组发布的<a href="http://code.google.com/p/grass-mud-horse/wiki/A_Brife_To_GrassMudHorse_Language" target="_blank">草泥马语言规范</a>及其<a href="http://compsoc.dur.ac.uk/whitespace/tutorial.php" target="_blank">英文翻译版</a></p>
<p>GrassMudMonkey利用JavaScript来实现词法分析和运行时，完整源代码：<a href="http://github.com/dexteryy/GrassMudMonkey/blob/master/grassmudmonkey.js" target="_blank">http://github.com/dexteryy/GrassMudMonkey/blob/master/grassmudmonkey.js</a></p>
<p>效果演示 / 在线的集成开发环境（提供控制台）：</p>
<p>默认示例里的程序通过循环输出1到10的整数</p>
<p><a href="http://www.limboy.com/demo/gmm/demo.html" target="_blank">[单独打开]</a><br />
<iframe src="http://www.limboy.com/demo/gmm/demo.html" width="490" height="600" frameborder="0"></iframe></p>
<p>注意事项1: 由于美学智慧上的分歧，GrassMudMonkey跟官方的JAVA版本有细微区别：不支持“河蟹”。</p>
<p>注意事项2：仅仅针对一两段程序做了基准测试，涵盖了大部分指令，但不排除有实现不一致的地方。</p>
<p>注释事项3：输入接口懒得写了，全部返回默认值，whitespace网站上的一些示例程序会因此无法运行。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.limboy.com/2010/03/21/grassmudmonkey/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>以国家之名</title>
		<link>http://www.limboy.com/2010/01/10/in-the-name-of-country/</link>
		<comments>http://www.limboy.com/2010/01/10/in-the-name-of-country/#comments</comments>
		<pubDate>Sun, 10 Jan 2010 15:51:45 +0000</pubDate>
		<dc:creator>Dexter.Yy</dc:creator>
				<category><![CDATA[Blogger]]></category>
		<category><![CDATA[代码]]></category>
		<category><![CDATA[日漫]]></category>
		<category><![CDATA[纯水]]></category>

		<guid isPermaLink="false">http://www.limboy.com/2010/01/10/in-the-name-of-country/</guid>
		<description><![CDATA[从我的Gmail里翻出的记录：

Mon, Feb 4, 2008 at 5:16 AM

subject: 注册信息
尊敬的用户，您的用户信息注册成功！用户名:dexter_yy
Thu, Feb 14, 2008 at 2:14 AM
subject: ICP备案审核通知（审核拒绝）
尊敬的用户:dexter_yy，很遗憾的通知您，您的ICP备案申请不能通过审核，拒绝原因是：您所备案的网站：请确认网站服务内容一栏填写是否准确.
接入商的核实意见：
(1) 信息不正确 请重新核对准确接入商


Mon, Feb 23, 2009 at 8:36 PM
subject: 关于网站备案用户执行“找回密码”操作后新密码的通知
尊敬的用户：dexter_yy，您于2009-02-23 20:33:34使用了备案用户找回密码功能，您找回的密码是：[马赛克]。请慎重保管注册密码！ 工业和信息化部网站备案系统
Wed, Mar 4, 2009 at 1:54 PM
subject: 关于ICP备案信息不符合备案要求退回修正的通知
尊敬的用户，很遗憾的通知您，您的ICP备案申请(limboy.com)，经[上海市通信管理局2]审核，不符合备案要求，现退回修改，原因请登陆系统查询。
Sat, Dec 12, 2009 at 2:59 PM
subject: 关于网站备案用户执行“找回密码”操作后新密码的通知
尊敬的用户：dexter_yy，您于2009-12-12 14:48:31使用了备案用户找回密码功能，您找回的密码是：XXXXXX。请慎重保管注册密码！ 工业和信息化部网站备案系统
Wed, Jan 6, 2010 at 10:45 AM
subject: 关于ICP备案申请审核通过的通知
尊敬的用户：您的ICP备案申请已通过审核,备案/许可证编号为: 沪ICP备10000943号 ，审核通过日期：2010-01-06。 
撒花～
本来我准备只贴出以上这些邮件内容，然后就结束本文点submit按钮发POST请求……但是这种把思考的工作托付给读者的写法，我还是有些不太放心，我担心这会让人误解我的意图，以为我是在嘲讽帝国衙门的政策法规和办事效率，不，如果这是你的理解，你错了，我是在嘲讽自己。
我的blog被关闭了大概有一两个月，在这段时间里，有很多人来问我，我都没回应，因为实在没什么好说的，没有黑幕，没有冤情，没有河蟹。我有充足的时间（早在一两年前我就知道不备案的后果），我有足够的帮助（盘古有专人为客户的备案提供支持），我有相对宽松的环境（直到现在，工信部仍然不会在处理申请的时候去审查网站的内容，甚至都不在乎网站是否存在，你只要去申请，只要你提供的信息不会对他们的工作流程造成困扰，他们就给你发ICP许可证），但我却把早就应该完成的备案，一直拖延到现在。都是我自己的错。
也许有人会说：你到底是真傻逼还是在装逼，错的首先是政府啊，你的blog被关闭，是因为现在这种荒谬愚蠢的国家政策，是因为统治阶层不懂得也不喜欢互联网的开放精神，是因为伟光正要控制信息，是因为工信部的备案系统太难用，是因为公务员的办事效率太低……总之，你怎么能不抱怨呢，你这不是麻木顺从的劣根性么
我会从土豆网里搜出一个视频来作为回答，不是什么经典大片，而是TV动画，如果不是宅男宅女应该就没看过——《地狱少女》第二部的第15话，标题是“以國家之名的墮落”，在这集故事里，女主角百合子的父亲是一个loser，家境穷困，生活很艰辛，他认为一切不幸的根源都是日本当时的首相大泉太一郎（这个名字应该不用注解罢），把全部时间投入到基层的助选活动中，支持另一个首相候选人，为此还不断借债，把自家的小工厂扔给妻子一人支撑。百合子在故事开始的时候就求助于地狱少女，希望把大泉首相立刻送进地狱，因为在这种家庭环境的影响下，她也认为只要没有大泉，人民生活就会幸福。但是后来，她的母亲劳累过度病倒了，在病床上，母亲说出了朴实的真相：
母亲：“不工作就不能生存……”
百合子：“果然这个国家的政治体制很异常！竟然要让人工作到弄跨身体才能生存！这都是大泉政府的错！”
母亲：“不是这样的……”
百合子：“什么不是啊，大泉首相上台前，我上小学的那个时候，生活不是还很轻松吗？！”
母亲：“更痛苦的时候也遇到过。可那时候一家人一起克服过来了，挥汗如雨的工作”。
百合子：“诶？”
虽然大泉的政策确实对百合子家工厂的衰败负有责任，但是导致境况越来越差的却是自己，不幸的根源是自己。自己的生活和自己的事业，最终还是需要自己的努力工作来改善，百合子的父亲把希望完全寄托在大环境的剧变上，但是大环境却不可能永远满足个人愿望，因为社会永远都由各种少数派和多数派拼凑而成，时代永远都像洪流一样让人身不由己的“前进”，正如比古清十郎说的那样：“时代和人心都有弊病，无论你有再强大的力量，也阻止不了时代的洪流。现今如此，今后亦然”。
最后，即使大环境真的剧变了，就能立刻体验到改善么？说到这里我想到了台湾的“马上就好”，想到了美国的“Change Has Come To [...]]]></description>
			<content:encoded><![CDATA[<p><a href='http://www.limboy.com/2010/01/10/in-the-name-of-country/change-1jpg/' rel='attachment wp-att-249' title='change-1.jpg'><img src='http://www.limboy.com/wp-content/uploads/2010/01/change-1.jpg' alt='change-1.jpg' style="margin:0 10px 0 0;float:left;" /></a>从我的Gmail里翻出的记录：</p>
<div style="margin-left:255px;">
<h4>Mon, Feb 4, 2008 at 5:16 AM</h4>
<blockquote><p>
subject: 注册信息</p>
<p>尊敬的用户，您的用户信息注册成功！用户名:dexter_yy</p></blockquote>
<h4>Thu, Feb 14, 2008 at 2:14 AM</h4>
<blockquote><p>subject: ICP备案审核通知（审核拒绝）</p>
<p>尊敬的用户:dexter_yy，很遗憾的通知您，您的ICP备案申请不能通过审核，拒绝原因是：您所备案的网站：请确认网站服务内容一栏填写是否准确.<br />
接入商的核实意见：<br />
(1) 信息不正确 请重新核对准确接入商</p></blockquote>
</div>
<p><span id="more-248"></span></p>
<h4>Mon, Feb 23, 2009 at 8:36 PM</h4>
<blockquote><p>subject: 关于网站备案用户执行“找回密码”操作后新密码的通知</p>
<p>尊敬的用户：dexter_yy，您于2009-02-23 20:33:34使用了备案用户找回密码功能，您找回的密码是：[马赛克]。请慎重保管注册密码！ 工业和信息化部网站备案系统</p></blockquote>
<h4>Wed, Mar 4, 2009 at 1:54 PM</h4>
<blockquote><p>subject: 关于ICP备案信息不符合备案要求退回修正的通知</p>
<p>尊敬的用户，很遗憾的通知您，您的ICP备案申请(limboy.com)，经[上海市通信管理局2]审核，不符合备案要求，现退回修改，原因请登陆系统查询。</p></blockquote>
<h4>Sat, Dec 12, 2009 at 2:59 PM</h4>
<blockquote><p>subject: 关于网站备案用户执行“找回密码”操作后新密码的通知</p>
<p>尊敬的用户：dexter_yy，您于2009-12-12 14:48:31使用了备案用户找回密码功能，您找回的密码是：XXXXXX。请慎重保管注册密码！ 工业和信息化部网站备案系统</p></blockquote>
<h4>Wed, Jan 6, 2010 at 10:45 AM</h4>
<blockquote><p>subject: 关于ICP备案申请审核通过的通知</p>
<p>尊敬的用户：您的ICP备案申请已通过审核,备案/许可证编号为: 沪ICP备10000943号 ，审核通过日期：2010-01-06。 </p></blockquote>
<p>撒花～</p>
<p>本来我准备只贴出以上这些邮件内容，然后就结束本文点submit按钮发POST请求……但是这种把思考的工作托付给读者的写法，我还是有些不太放心，我担心这会让人误解我的意图，以为我是在嘲讽帝国衙门的政策法规和办事效率，不，如果这是你的理解，你错了，我是在嘲讽自己。</p>
<p>我的blog被关闭了大概有一两个月，在这段时间里，有很多人来问我，我都没回应，因为实在没什么好说的，没有黑幕，没有冤情，没有河蟹。我有充足的时间（早在一两年前我就知道不备案的后果），我有足够的帮助（<a href="http://www.paangood.com/index.php" target="_blank">盘古</a>有专人为客户的备案提供支持），我有相对宽松的环境（直到现在，工信部仍然不会在处理申请的时候去审查网站的内容，甚至都不在乎网站是否存在，你只要去申请，只要你提供的信息不会对他们的工作流程造成困扰，他们就给你发ICP许可证），但我却把早就应该完成的备案，一直拖延到现在。都是我自己的错。</p>
<p>也许有人会说：你到底是真傻逼还是在装逼，错的首先是政府啊，你的blog被关闭，是因为现在这种荒谬愚蠢的国家政策，是因为统治阶层不懂得也不喜欢互联网的开放精神，是因为伟光正要控制信息，是因为工信部的<a target="_blank" href="http://www.google.com/search?q=%E5%B7%A5%E4%BF%A1%E9%83%A8%E7%BD%91%E7%AB%99%E5%A4%87%E6%A1%88%E7%B3%BB%E7%BB%9F%E5%A4%AA%E7%83%82%E6%98%AF%E5%A4%A7%E9%87%8F%E7%BD%91%E7%AB%99%E6%B2%A1%E6%9C%89%E5%A4%87%E6%A1%88%E7%9A%84%E4%B8%BB%E8%A6%81%E5%8E%9F%E5%9B%A0">备案系统太难用</a>，是因为公务员的办事效率太低……总之，你怎么能不抱怨呢，你这不是麻木顺从的劣根性么</p>
<p>我会从土豆网里搜出一个视频来作为回答，不是什么经典大片，而是TV动画，如果不是宅男宅女应该就没看过——《地狱少女》第二部的第15话，标题是“以國家之名的墮落”，在这集故事里，女主角百合子的父亲是一个loser，家境穷困，生活很艰辛，他认为一切不幸的根源都是日本当时的首相大泉太一郎（这个名字应该不用注解罢），把全部时间投入到基层的助选活动中，支持另一个首相候选人，为此还不断借债，把自家的小工厂扔给妻子一人支撑。百合子在故事开始的时候就求助于地狱少女，希望把大泉首相立刻送进地狱，因为在这种家庭环境的影响下，她也认为只要没有大泉，人民生活就会幸福。但是后来，她的母亲劳累过度病倒了，在病床上，母亲说出了朴实的真相：</p>
<p>母亲：“不工作就不能生存……”<br />
百合子：“果然这个国家的政治体制很异常！竟然要让人工作到弄跨身体才能生存！这都是大泉政府的错！”<br />
母亲：“不是这样的……”<br />
百合子：“什么不是啊，大泉首相上台前，我上小学的那个时候，生活不是还很轻松吗？！”<br />
母亲：“更痛苦的时候也遇到过。可那时候一家人一起克服过来了，挥汗如雨的工作”。<br />
百合子：“诶？”</p>
<p>虽然大泉的政策确实对百合子家工厂的衰败负有责任，但是导致境况越来越差的却是自己，不幸的根源是自己。自己的生活和自己的事业，最终还是需要自己的努力工作来改善，百合子的父亲把希望完全寄托在大环境的剧变上，但是大环境却不可能永远满足个人愿望，因为社会永远都由各种少数派和多数派拼凑而成，时代永远都像洪流一样让人身不由己的“前进”，正如比古清十郎说的那样：“时代和人心都有弊病，无论你有再强大的力量，也阻止不了时代的洪流。现今如此，今后亦然”。</p>
<p>最后，即使大环境真的剧变了，就能立刻体验到改善么？说到这里我想到了台湾的“马上就好”，想到了美国的“Change Has Come To America”，想到了日本的“政权更迭”……只要自己不行动，改善就不可能从天而降。如果等到那时才行动，就更不可能“马上就好”。既然早晚要行动，为什么不从现在就开始？</p>
<p>以国家之名的懒惰，以国家之名的松懈，以国家之名的放弃，也许能赢得一些同情和理解，但是最终失去那些东西的仍然是我们自己。</p>
<p>最后，百合子委托给地狱少女的不是大泉首相，而是自己的父亲。完整视频：</p>
<p><object width="500" height="380"><param name="movie" value="http://www.tudou.com/v/734oFQo5HwE"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><param name="wmode" value="opaque"></param><embed src="http://www.tudou.com/v/734oFQo5HwE" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" wmode="opaque" width="420" height="363"></embed></object></p>
<p>PS：其实我并不是因为没及时备案就妄想出这些，而是因为长时间以来在twitter上体验到的氛围，积压在心底。</p>
<p>PS2：我的“拖延”习惯貌似是一种症状，叫“Procrastination”，由于最近帝国对网络的打击，相关文章的链接失效了^_^b&#8230;..请自行搜索……如果不是看了那些文章，我还以为这是个性呢……</p>
<p>PS3：虽然我常常几个月都不更新blog，但是在blog关掉的这段时间里，却叛逆似的积压了好几篇……有的发在论坛，有的放在evernote里，接下来会找时间发出来，希望不要拖延-___-b</p>
]]></content:encoded>
			<wfw:commentRss>http://www.limboy.com/2010/01/10/in-the-name-of-country/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>我觉得做NARUTO TV动画的人应该切腹</title>
		<link>http://www.limboy.com/2009/09/20/naruto-tv-sucks/</link>
		<comments>http://www.limboy.com/2009/09/20/naruto-tv-sucks/#comments</comments>
		<pubDate>Sun, 20 Sep 2009 15:45:48 +0000</pubDate>
		<dc:creator>Dexter.Yy</dc:creator>
				<category><![CDATA[代码]]></category>
		<category><![CDATA[动漫]]></category>
		<category><![CDATA[土豆网]]></category>
		<category><![CDATA[日漫]]></category>
		<category><![CDATA[游戏]]></category>
		<category><![CDATA[音乐]]></category>

		<guid isPermaLink="false">http://www.limboy.com/2009/09/20/naruto-tv-sucks/</guid>
		<description><![CDATA[虽然早在火影沦为四大民工漫之首的若干年前，我就已经没怎么追了（漫画偶尔看看），但是早期几个章节的tv动画（比如卡卡西vs再不斩，中忍考试李洛克vs我爱罗）曾经让我非常非常感动，我不是指那些纠结的人性和搅基的情感之类的玩意让我感动，是指镜头变化和速度感都非常华丽的打斗场面，最近的一部能让我有类似热血感觉的作品是BONES的SOUL EATER。
那段时期大概也是西尾铁也和他手下那帮超强的作画人员还在全力参与的阶段，西尾铁也这个人在国内不算出名，但是他参与过原画的几乎全是神作：《攻壳机动队SAC GIG》，《交响诗篇eureka7》，《精灵守护者》，《东之伊甸》（刚完结，前段时间最喜欢的），押井守最近的剧场动画《空中杀手》（The Sky Crawlers）的人设也是他，主要人物的脸和身体就像火影里一样圆润……


Rock Lee vs 我爱罗的一个MAD版

精灵守护者里的第一场打斗片段

精灵守护者里评价最高的打斗片段

西尾铁也并不是一个人在战斗，他的背后是日本最强（在西方人眼里，对我来说只能算“之一”，BONES，MADHOUSE等公司也能保证必出精品）的动画公司IG，跟他同级别能保证作品质量的强者还有：沖浦啓之（罗德斯岛战记原画，MEMORIES原画，攻壳GIS作画监督，COWBOY BEBOP剧场版OP分镜，演出和原画），黄瀬和哉（天空战记作画监督，EVA TV/旧剧场版/新剧场版作画监督，浪客剑心原画，攻壳SAC SSS原画），此三人合称IG作画三大神。他们参与过的神作不止这些，我只拿自己熟悉的举例。

Cowboy Bebop剧场版天国之扉的op《Ask DNA》，菅野洋子作曲
实际上早期的火影创作团队简直是精英云集，比如音乐是由天才作曲家増田俊郎（他为《虫师》创作的两张碟可能更有名）和擅长日本民俗乐器的摇滚乐队“六三四Musashi”（演奏尺八的那位：http://www.douban.com/subject/2213500/）合作的，包括前三张OST专辑，我最喜欢其中的摇滚部分，比如OST1里的Need To Be Strong和OST3里的自来也主题。

自来也主题曲
但是像西尾这样的人才不可能一直把精力花在柯南般的没完没了的国民动画上，再加上投入的成本大幅降低，为避免进度赶上漫画而搞出的大量脑残般的回忆段落和原创剧情，早期那些热血的动作场面和CG再也看不到了……后期的火影tv版给我的最深刻印象是：主角们在树和树之间跳跃可以花上几十分钟的片长，其滞空时间和思维活动的复杂深邃，远远胜过当年灌篮高手在角色跳投或抢篮板过程中让观众发表五分钟评论的场面。
昨天晚上哥很寂寞，一边看书一边在台式机的chrome上挂豆丸，无意中发现火影最新的OP《萤之光》很好听（可能是因为结合了画面才好听，生物股长这个乐队在红白歌会里看到过，没什么特殊印象），在豆丸里切换了几个相关视频，发现一个MAD版本（MAD即MADMOVIE，这个词起源很宅，反正在日本动漫社区里指二次创作影像），大部分画面是从PS3游戏Naruto: Ultimate Ninja Storm里剪辑出来的，身为一个没买过任何次世代主机被别人主动赠与X360长达两周时间连GTA4都没通关的坚定的久经考验的PC玩家，当时我就震精了……靠这战斗画面太华丽了口牙！速度感满分（比如阿斯玛的斩击，日向雏田的八卦六十四掌），还表现出了漫画里没出现过传说中的技能（四代火影的时空忍术，效果确实像金色闪光）。相比之下现在的动画究竟算什么水平口牙！为什么差距这么大，难道就因为南梦宫更有钱么（纠正……好像是开发.hack的那个工作室搞的），关键还是认真的充满爱的态度罢！
视频来源是niconico，土豆上只能找到三部，基本上所有人物都出场了，优酷上搜不到：





然则画面实在是太模糊了，土豆的MPS系统应该不至于把好片源压成这个鬼样子，因此，这就是我写这篇blog的目的叻！虽然你看完之后可能以为我在发软文……咳……但是……人家没有骗你～人家真的就是想知道这个视频的出处地址或者其他清晰版本嘛～～跪求！（我把别人以前共享的niconico帐号给忘了T___T）
P.S. 最后我要指出……在写这篇blog的时间内很轻松的搜出以上关键词比较特殊的视频，感觉土豆自己研发的搜索系统还是蛮好用的喔活活活活……唯一失败的是soul eater的打斗片段……如果在youtube上搜索“Mifune vs Blackstar”，一定是大把的两三分钟左右的片段，而国内视频用户上传的几乎全是25分钟左右的完整动画……汗……
]]></description>
			<content:encoded><![CDATA[<p><a href='http://www.limboy.com/2009/09/20/naruto-tv-sucks/rock_leepng/' rel='attachment wp-att-244' title='rock_lee.png'><img src='http://www.limboy.com/wp-content/uploads/2009/09/rock_lee.png' alt='rock_lee.png' style="margin:0 10px;float:left;width:150px;border:0" /></a>虽然早在火影沦为四大民工漫之首的若干年前，我就已经没怎么追了（漫画偶尔看看），但是早期几个章节的tv动画（比如卡卡西vs再不斩，中忍考试李洛克vs我爱罗）曾经让我非常非常感动，我不是指那些纠结的人性和搅基的情感之类的玩意让我感动，是指镜头变化和速度感都非常华丽的打斗场面，最近的一部能让我有类似热血感觉的作品是BONES的SOUL EATER。</p>
<p>那段时期大概也是西尾铁也和他手下那帮超强的作画人员还在全力参与的阶段，西尾铁也这个人在国内不算出名，但是他参与过原画的几乎全是神作：《攻壳机动队SAC GIG》，《交响诗篇eureka7》，《精灵守护者》，《东之伊甸》（刚完结，前段时间最喜欢的），押井守最近的剧场动画《空中杀手》（The Sky Crawlers）的人设也是他，主要人物的脸和身体就像火影里一样圆润……<span id="more-243"></span></p>
<div style="clear:left;">
<p><object width="420" height="363"><param name="movie" value="http://www.tudou.com/v/LQ3MzZhB62o"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><param name="wmode" value="opaque"></param><embed src="http://www.tudou.com/v/LQ3MzZhB62o" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" wmode="opaque" width="420" height="363"></embed></object><br />
<em>Rock Lee vs 我爱罗的一个MAD版</em></p>
<p><object width="420" height="363"><param name="movie" value="http://www.tudou.com/v/qKYKfAmdlfE"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><param name="wmode" value="opaque"></param><embed src="http://www.tudou.com/v/qKYKfAmdlfE" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" wmode="opaque" width="420" height="363"></embed></object><br />
<em>精灵守护者里的第一场打斗片段</em></p>
<p><object width="420" height="363"><param name="movie" value="http://www.tudou.com/v/n691HdFt-ak"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><param name="wmode" value="opaque"></param><embed src="http://www.tudou.com/v/n691HdFt-ak" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" wmode="opaque" width="420" height="363"></embed></object><br />
<em>精灵守护者里评价最高的打斗片段</em>
</div>
<p>西尾铁也并不是一个人在战斗，他的背后是日本最强（在西方人眼里，对我来说只能算“之一”，BONES，MADHOUSE等公司也能保证必出精品）的动画公司IG，跟他同级别能保证作品质量的强者还有：沖浦啓之（罗德斯岛战记原画，MEMORIES原画，攻壳GIS作画监督，COWBOY BEBOP剧场版OP分镜，演出和原画），黄瀬和哉（天空战记作画监督，EVA TV/旧剧场版/新剧场版作画监督，浪客剑心原画，攻壳SAC SSS原画），此三人合称IG作画三大神。他们参与过的神作不止这些，我只拿自己熟悉的举例。</p>
<p><object width="420" height="363"><param name="movie" value="http://www.tudou.com/v/cX7LR76ik2g"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><param name="wmode" value="opaque"></param><embed src="http://www.tudou.com/v/cX7LR76ik2g" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" wmode="opaque" width="420" height="363"></embed></object><br />
<em>Cowboy Bebop剧场版天国之扉的op《Ask DNA》，菅野洋子作曲</em></p>
<p>实际上早期的火影创作团队简直是精英云集，比如音乐是由天才作曲家増田俊郎（他为《虫师》创作的两张碟可能更有名）和擅长日本民俗乐器的摇滚乐队“六三四Musashi”（演奏尺八的那位：<a href="http://www.douban.com/subject/2213500/" target="_blank">http://www.douban.com/subject/2213500/</a>）合作的，包括前三张OST专辑，我最喜欢其中的摇滚部分，比如OST1里的Need To Be Strong和OST3里的自来也主题。</p>
<p><object width="420" height="30"><param name="movie" value="http://www.tudou.com/v/1aV_pEi2ix4"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><param name="wmode" value="opaque"></param><embed src="http://www.tudou.com/v/1aV_pEi2ix4" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" wmode="opaque" width="420" height="30"></embed></object><br />
<em>自来也主题曲</em></p>
<p>但是像西尾这样的人才不可能一直把精力花在柯南般的没完没了的国民动画上，再加上投入的成本大幅降低，为避免进度赶上漫画而搞出的大量脑残般的回忆段落和原创剧情，早期那些热血的动作场面和CG再也看不到了……后期的火影tv版给我的最深刻印象是：主角们在树和树之间跳跃可以花上几十分钟的片长，其滞空时间和思维活动的复杂深邃，远远胜过当年灌篮高手在角色跳投或抢篮板过程中让观众发表五分钟评论的场面。</p>
<p>昨天晚上<del>哥很寂寞</del>，一边看书一边在台式机的chrome上挂<a href="http://douwan.tudou.com" target="_blank">豆丸</a>，无意中发现火影最新的OP《萤之光》很好听（可能是因为结合了画面才好听，生物股长这个乐队在红白歌会里看到过，没什么特殊印象），在豆丸里切换了几个相关视频，发现一个MAD版本（MAD即MADMOVIE，这个词起源很宅，反正在日本动漫社区里指二次创作影像），大部分画面是从PS3游戏<a href="http://ps3.ign.com/articles/867/867121p1.html" target="_blank">Naruto: Ultimate Ninja Storm</a>里剪辑出来的，身为一个没买过任何次世代主机被别人主动赠与X360长达两周时间连GTA4都没通关的坚定的久经考验的PC玩家，当时我就震精了……靠这战斗画面太华丽了口牙！速度感满分（比如阿斯玛的斩击，日向雏田的八卦六十四掌），还表现出了漫画里没出现过传说中的技能（四代火影的时空忍术，效果确实像金色闪光）。相比之下现在的动画究竟算什么水平口牙！为什么差距这么大，难道就因为<del>南梦宫更有钱么</del>（纠正……好像是开发.hack的那个工作室搞的），关键还是认真的充满爱的态度罢！</p>
<p>视频来源是niconico，土豆上只能找到三部，基本上所有人物都出场了，优酷上搜不到：</p>
<p><object width="420" height="363"><param name="movie" value="http://www.tudou.com/v/orxR5UdpLQE"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><param name="wmode" value="opaque"></param><embed src="http://www.tudou.com/v/orxR5UdpLQE" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" wmode="opaque" width="420" height="363"></embed></object><br />
<br/><br />
<object width="420" height="363"><param name="movie" value="http://www.tudou.com/v/pbnBfT4a25Y"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><param name="wmode" value="opaque"></param><embed src="http://www.tudou.com/v/pbnBfT4a25Y" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" wmode="opaque" width="420" height="363"></embed></object><br />
<br/><br />
<object width="420" height="363"><param name="movie" value="http://www.tudou.com/v/tfJv8DJeNHs"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><param name="wmode" value="opaque"></param><embed src="http://www.tudou.com/v/tfJv8DJeNHs" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" wmode="opaque" width="420" height="363"></embed></object></p>
<p>然则画面实在是太模糊了，土豆的MPS系统应该不至于把好片源压成这个鬼样子，因此，这就是我写这篇blog的目的叻！虽然你看完之后可能以为我在发软文……咳……但是……人家没有骗你～人家真的就是想知道这个视频的出处地址或者其他清晰版本嘛～～跪求！（我把别人以前共享的niconico帐号给忘了T___T）</p>
<p>P.S. 最后我要指出……在写这篇blog的时间内很轻松的搜出以上关键词比较特殊的视频，感觉土豆自己研发的搜索系统还是蛮好用的喔活活活活……唯一失败的是soul eater的打斗片段……如果在youtube上搜索“Mifune vs Blackstar”，一定是大把的两三分钟左右的片段，而国内视频用户上传的几乎全是25分钟左右的完整动画……汗……</p>
]]></content:encoded>
			<wfw:commentRss>http://www.limboy.com/2009/09/20/naruto-tv-sucks/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>[内销转出口]寻找最好的JavaScript面向对象模式和封装结构</title>
		<link>http://www.limboy.com/2009/09/20/tudou-javascript-oop-and-module-guideline/</link>
		<comments>http://www.limboy.com/2009/09/20/tudou-javascript-oop-and-module-guideline/#comments</comments>
		<pubDate>Sun, 20 Sep 2009 05:02:22 +0000</pubDate>
		<dc:creator>Dexter.Yy</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[代码]]></category>
		<category><![CDATA[土豆网]]></category>

		<guid isPermaLink="false">http://www.limboy.com/2009/09/20/tudou-javascript-oop-and-module-guideline/</guid>
		<description><![CDATA[好久不见，这次发的不是笔记啦，是我在公司内部的前端wiki上更新的文档……这个抛弃所有wiki语法要求用户直接手写语义化html用json配置导航的wiki排版相当漂亮，让我这样的懒人也有了码字的欲望，发起人小麦实在系功德无量……

这篇文章去年就准备写，想用循序渐进的形式推演出一个Module Pattern的最佳实践，不过想法越多，归纳总结表达出来的成本就越高，所以一直拖延……这次发的文档是一个简化版，去掉了各式各样乱七八糟的写法，只包含几个常用的，说明文字也不多主要看代码-__-b……初衷是作为给土豆前端team里新来的同事看的提纲（对了由于某人叛逃到产品设计部门，现在又空出一个名额，有兴趣的同学抓紧时间投简历，这次是魔都总部的职位，不是成都的），所以要解释一下，文档中提到的TUI是一个js库（名字是很俗，不过我上次发现某年纪一大把的人也跟我一样俗），土豆一直采用双库并行（不要看成双工并行…）的形式，在紧跟开源社区发展的同时自己掌控所有环节和基础架构，没有使用jQuery UI和那套基于DOM的插件结构，而jQuery自己几乎不提供OOP工具（这是好事），实际上自己创建这类工具非常简单快捷，相关的代码我提取了一下直接帖在末尾了，仅供参考。
另外，为了符合Nicholas Zakas在最近的国际会议上传达的精神，我修改了若干变量名跟他ppt里的例子保持一致——这件事教育我们，平时多上slideshow.net对保持先进性是多么重要。
Tudou&#8217;s JavaScript Guideline &#8212; OOP and Module
介绍土豆在面向对象和模块化设计方面的工具和实践

&#8220;Don&#8217;t Repeat Yourself.&#8221; (DRY)
&#8220;Rather than construction, programming is more like gardening.&#8221;
Quote from: Andy Hunt and Dave Thomas, The Pragmatic Programmer
			

索引

创建类，继承，混入，实例化
模块化 Module Pattern
沙盒，模块间的解耦，与外部通信
按需加载模块 On-demand Lazy Load
总结


创建类，继承，混入，实例化
我们依赖的核心工具是TUI.clone
简洁的，支持私有属性，不需要prototype的写法：
JS是基于原型而不是基于类的面向对象语言，JS是“无类型”的，类是仿造出来的概念，实质只有对象。
new只是用来复制对象，构造函数只是用来返回对象, 两者对JS的OOP来说并不是必须的。
var dog = function(options){
&#160; &#160; var&#160;privateAttr = 1; //私有属性
&#160; &#160; var&#160;private_method = function(){}; //私有方法
&#160; &#160; return&#160;{
&#160; &#160; &#160; &#160; option: options, [...]]]></description>
			<content:encoded><![CDATA[<p>好久不见，这次发的不是笔记啦，是我在公司内部的前端wiki上更新的文档……这个抛弃所有wiki语法要求用户直接手写语义化html用json配置导航的wiki排版相当漂亮，让我这样的懒人也有了码字的欲望，发起人小麦实在系功德无量……</p>
<p><a href='http://www.limboy.com/wp-content/uploads/2009/09/picture-2.png' title='picture-2.png' target="_blank"><img src='http://www.limboy.com/wp-content/uploads/2009/09/picture-2.png' alt='picture-2.png' style="width:200px;margin:5px;" /></a><a href='http://www.limboy.com/wp-content/uploads/2009/09/picture-3.png'  target="_blank"><img src='http://www.limboy.com/wp-content/uploads/2009/09/picture-3.png' alt='picture-3.png'  style="width:200px;margin:5px;" /></a></p>
<p>这篇文章去年就准备写，想用循序渐进的形式推演出一个<a href="http://www.yuiblog.com/blog/2007/06/12/module-pattern/" target="_blank">Module Pattern</a>的最佳实践，不过想法越多，归纳总结表达出来的成本就越高，所以一直拖延……这次发的文档是一个简化版，去掉了各式各样乱七八糟的写法，只包含几个常用的，说明文字也不多主要看代码-__-b……初衷是作为给土豆前端team里新来的同事看的提纲（对了由于某人叛逃到产品设计部门，现在又空出一个名额，有兴趣的同学抓紧时间<a href="http://www.mikkolee.com/256" target="_blank">投简历</a>，这次是魔都总部的职位，不是成都的），所以要解释一下<span id="more-240"></span>，文档中提到的<var>TUI</var>是一个js库（名字是很俗，不过我上次发现某年纪一大把的人也跟我<a href="http://blog.digg.com/?p=621" target="_blank">一样俗</a>），土豆一直采用双库并行（不要看成双工并行…）的形式，在紧跟开源社区发展的同时自己掌控所有环节和基础架构，没有使用jQuery UI和那套基于DOM的插件结构，而jQuery自己几乎不提供OOP工具（这是好事），实际上自己创建这类工具非常简单快捷，相关的代码我提取了一下直接帖在末尾了，仅供参考。</p>
<p>另外，为了符合Nicholas Zakas在最近的<a href="http://www.yuiblog.com/blog/2009/09/17/video-bayjax-sept-09/" target="_blank">国际会议</a>上传达的精神，我修改了若干变量名跟他<a href="http://www.slideshare.net/nzakas/scalable-javascript-application-architecture" target="_blank">ppt</a>里的例子保持一致——这件事教育我们，平时多上slideshow.net对保持先进性是多么重要。</p>
<h2>Tudou&#8217;s JavaScript Guideline &#8212; OOP and Module</h2>
<p><em>介绍土豆在面向对象和模块化设计方面的工具和实践</em></p>
<blockquote>
<p>&#8220;Don&#8217;t Repeat Yourself.&#8221; (DRY)</p>
<p>&#8220;Rather than construction, programming is more like gardening.&#8221;</p>
<p><cite>Quote from: Andy Hunt and Dave Thomas, The Pragmatic Programmer</cite>
			</p></blockquote>
<div class="section">
<h2>索引</h2>
<ol>
<li><a href="#sec-1">创建类，继承，混入，实例化</a></li>
<li><a href="#sec-2">模块化 Module Pattern</a></li>
<li><a href="#sec-3">沙盒，模块间的解耦，与外部通信</a></li>
<li><a href="#sec-4">按需加载模块 On-demand Lazy Load</a></li>
<li><a href="#sec-5">总结</a></li>
</ol></div>
<div class="section" id="sec-1">
<h2>创建类，继承，混入，实例化</h2>
<p>我们依赖的核心工具是<var>TUI.clone</var></p>
<h3>简洁的，支持私有属性，不需要prototype的写法：</h3>
<p>JS是基于原型而不是基于类的面向对象语言，JS是“无类型”的，类是仿造出来的概念，实质只有对象。<br />
<var>new</var>只是用来复制对象，构造函数只是用来返回对象, 两者对JS的OOP来说并不是必须的。</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Green;">var</span><span style="color: Gray;"> </span><span style="color: Blue;">dog</span><span style="color: Gray;"> = </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">options</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">privateAttr</span><span style="color: Gray;"> = </span><span style="color: Maroon;">1</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//私有属性</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">private_method</span><span style="color: Gray;"> = </span><span style="color: Green;">function</span><span style="color: Olive;">(){}</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//私有方法</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">option</span><span style="color: Gray;">: </span><span style="color: Blue;">options</span><span style="color: Gray;">, </span><span style="color: #ffa500;">//实例属性</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">method1</span><span style="color: Gray;">: </span><span style="color: Green;">function</span><span style="color: Olive;">(){}</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">}</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">xiaobai</span><span style="color: Gray;"> = </span><span style="color: Blue;">dog</span><span style="color: Olive;">({})</span><span style="color: Gray;">;</span></li></ol></div>
<ul>
<li>对私有属性/方法的支持比较好</li>
<li>最适合单例模式(Singleton)</li>
<li>延迟单例的初始化，提高页面初始化的速度</li>
<li>缺点：对继承的支持不佳</li>
<li>缺点：在需要频繁创建大量对象，而方法非常多的场合，浪费资源（因为每个实例的方法指向的都是不同的函数对象，每次实例化都要重新生成所有函数）</li>
</ul>
<p>在第2个缺点的场合，传统的prototype写法效率更高，支持继承，但是代码分散，不易读，TUI.clone提供了更好的写法——</p>
<h3>传统的、支持继承的、仿Ruby风格的Class写法：</h3>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: #ffa500;">//创建新类</span></li>
<li><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">Dog</span><span style="color: Gray;"> = </span><span style="color: Blue;">TUI</span><span style="color: Gray;">.</span><span style="color: Blue;">newClass</span><span style="color: Olive;">({</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">initialize</span><span style="color: Gray;">: </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">options</span><span style="color: Olive;">){</span><span style="color: Gray;">&nbsp;</span><span style="color: #ffa500;">//构造函数</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">this</span><span style="color: Gray;">.</span><span style="color: Blue;">option</span><span style="color: Gray;"> = </span><span style="color: Blue;">options</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span></li>
<li><span style="color: Olive;">})</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: #ffa500;">//实例化</span></li>
<li><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">xiaobai</span><span style="color: Gray;"> = </span><span style="color: Green;">new</span><span style="color: Gray;"> </span><span style="color: Blue;">Dog</span><span style="color: Olive;">()</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: #ffa500;">//继承</span></li>
<li><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">Cat</span><span style="color: Gray;"> = </span><span style="color: Blue;">TUI</span><span style="color: Gray;">.</span><span style="color: Blue;">newClass</span><span style="color: Olive;">(</span><span style="color: Blue;">dog</span><span style="color: Gray;">, </span><span style="color: Olive;">{</span><span style="color: Gray;"> </span><span style="color: #ffa500;">//只允许单继承</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">mixin</span><span style="color: Gray;">: </span><span style="color: Olive;">[</span><span style="color: Blue;">TUI</span><span style="color: Gray;">.</span><span style="color: Blue;">event</span><span style="color: Olive;">]</span><span style="color: Gray;">, </span><span style="color: #ffa500;">//混入其他方法</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">initialize</span><span style="color: Gray;">: </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">options</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">this</span><span style="color: Gray;">.</span><span style="color: Blue;">superClass</span><span style="color: Gray;">.</span><span style="color: Blue;">call</span><span style="color: Olive;">(</span><span style="color: Green;">this</span><span style="color: Gray;">, </span><span style="color: Blue;">arguments</span><span style="color: Olive;">)</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//调用父类构造函数</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span></li>
<li><span style="color: Olive;">})</span><span style="color: Gray;">;</span></li></ol></div>
<ul>
<li>风格类似<var>mootools</var>的<var>new Class</var></li>
<li><var>TUI.newClass</var>只是<var>TUI.clone</var>的封装</li>
<li><var>mixin</var>相当于在构造函数里<var>$.extend(this.prototype, TUI.event)</var></li>
<li>实际上应该少用继承，多用mixin和组合模式，后者更符合JS的特点</li>
<li>缺点：封装效果不好，不支持私有属性和方法</li>
</ul>
<p><var>TUI.clone</var>既可以复制构造函数的<var>prototype</var>，也可以直接复制对象（跟jQuery.extend不同，依靠原型继承），所以利用它直接生成实例。</p>
<p>这样可以在不引入<var>prototype</var>和语法糖的情况下把第一种方法改造的同样高效——</p>
<h3>对象克隆工厂的写法：</h3>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Green;">var</span><span style="color: Gray;"> </span><span style="color: Blue;">dog</span><span style="color: Gray;"> = </span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">jQuery</span><span style="color: Gray;">, </span><span style="color: Blue;">TUI</span><span style="color: Olive;">){</span><span style="color: Gray;"> </span><span style="color: #ffa500;">//传入需要访问的全局命名空间</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">a</span><span style="color: Gray;"> = </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">xxx</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//不作为状态的私有属性</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">private_method</span><span style="color: Gray;"> = </span><span style="color: Green;">function</span><span style="color: Olive;">(){</span><span style="color: Gray;"> </span><span style="color: #ffa500;">//私有方法</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">alert</span><span style="color: Olive;">(</span><span style="color: Green;">this</span><span style="color: Gray;">.</span><span style="color: Blue;">option</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">PublicObj</span><span style="color: Gray;"> = </span><span style="color: Olive;">{</span><span style="color: Gray;"> </span><span style="color: #ffa500;">//相当于prototype对象</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">method1</span><span style="color: Gray;">: </span><span style="color: Green;">function</span><span style="color: Olive;">(){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">private_method</span><span style="color: Gray;">.</span><span style="color: Blue;">call</span><span style="color: Olive;">(</span><span style="color: Green;">this</span><span style="color: Olive;">)</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//访问私有方法, 共享状态</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">}</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">options</span><span style="color: Olive;">){</span><span style="color: Gray;"> </span><span style="color: #ffa500;">//对象工厂</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">obj</span><span style="color: Gray;"> = </span><span style="color: Blue;">TUI</span><span style="color: Gray;">.</span><span style="color: Blue;">clone</span><span style="color: Olive;">(</span><span style="color: Blue;">PublicObj</span><span style="color: Olive;">)</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//克隆</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">obj</span><span style="color: Gray;">.</span><span style="color: Blue;">aption</span><span style="color: Gray;"> = </span><span style="color: Blue;">options</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//构造函数中的常规任务</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; $.</span><span style="color: Blue;">extend</span><span style="color: Olive;">(</span><span style="color: Blue;">obj</span><span style="color: Gray;">, </span><span style="color: Blue;">cat</span><span style="color: Olive;">)</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//mixin其他对象的方法</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">obj</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">})(</span><span style="color: Blue;">jQuery</span><span style="color: Gray;">, </span><span style="color: Blue;">TUI</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">xiaobai</span><span style="color: Gray;"> = </span><span style="color: Blue;">dog</span><span style="color: Olive;">({})</span><span style="color: Gray;">;</span></li></ol></div>
<ul>
<li>效率高，封装好，耦合少易于修改和扩展</li>
<li>缺点：私有属性不能作为实例状态</li>
</ul>
<p>把以上第一种方法和第三种方法结合互补，为module模式——</p>
</p></div>
<div class="section" id="sec-2">
<h2>模块化 Module Pattern</h2>
<p>核心工具是<var>TUI.module</var></p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">TUI</span><span style="color: Gray;">.</span><span style="color: Blue;">widget</span><span style="color: Gray;">.</span><span style="color: Blue;">dog</span><span style="color: Gray;"> = </span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Gray;">$, </span><span style="color: Blue;">TUI</span><span style="color: Olive;">){</span><span style="color: Gray;"> </span><span style="color: #ffa500;">//除了库的命名空间，尽量不访问全局变量</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: #ffa500;">//所有模块代码都封闭在这个区域内</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">a</span><span style="color: Gray;"> = </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">xxx</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//不作为状态的私有属性</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">private_method</span><span style="color: Gray;"> = </span><span style="color: Green;">function</span><span style="color: Olive;">(){</span><span style="color: Gray;"> </span><span style="color: #ffa500;">//私有方法</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">alert</span><span style="color: Olive;">(</span><span style="color: Green;">this</span><span style="color: Gray;">.</span><span style="color: Blue;">option</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">privateObj</span><span style="color: Gray;"> = </span><span style="color: Olive;">{}</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//可作为状态的私有属性</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">privateAttr</span><span style="color: Gray;"> = </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">name</span><span style="color: Gray;">, </span><span style="color: Blue;">value</span><span style="color: Olive;">){</span><span style="color: Gray;"> </span><span style="color: #ffa500;">//读写私有属性的方法，只能在内部使用</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">p</span><span style="color: Gray;"> = </span><span style="color: Green;">private</span><span style="color: Olive;">[</span><span style="color: Green;">this</span><span style="color: Gray;">.</span><span style="color: Blue;">objectId</span><span style="color: Olive;">]</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">if</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">(</span><span style="color: Gray;">!</span><span style="color: Blue;">p</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">p</span><span style="color: Gray;"> = </span><span style="color: Green;">private</span><span style="color: Olive;">[</span><span style="color: Green;">this</span><span style="color: Gray;">.</span><span style="color: Blue;">objectId</span><span style="color: Olive;">]</span><span style="color: Gray;"> = </span><span style="color: Olive;">{}</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">if</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">(</span><span style="color: Blue;">value</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">p</span><span style="color: Olive;">[</span><span style="color: Blue;">name</span><span style="color: Olive;">]</span><span style="color: Gray;"> = </span><span style="color: Blue;">value</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">p</span><span style="color: Olive;">[</span><span style="color: Blue;">name</span><span style="color: Olive;">]</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">TUI</span><span style="color: Gray;">.</span><span style="color: Blue;">dog</span><span style="color: Gray;"> = </span><span style="color: Blue;">TUI</span><span style="color: Gray;">.</span><span style="color: Blue;">newClass</span><span style="color: Olive;">(</span><span style="color: Blue;">parentClass</span><span style="color: Gray;">, </span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">mixin</span><span style="color: Gray;">: </span><span style="color: Olive;">[</span><span style="color: Blue;">TUI</span><span style="color: Gray;">.</span><span style="color: Blue;">event</span><span style="color: Olive;">]</span><span style="color: Gray;">, </span><span style="color: #ffa500;">//混入其他方法</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">initialize</span><span style="color: Gray;">: </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">options</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">this</span><span style="color: Gray;">.</span><span style="color: Blue;">superClass</span><span style="color: Gray;">.</span><span style="color: Blue;">call</span><span style="color: Olive;">(</span><span style="color: Green;">this</span><span style="color: Gray;">, </span><span style="color: Blue;">arguments</span><span style="color: Olive;">)</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//访问父类构造函数</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">public_method</span><span style="color: Gray;">: </span><span style="color: Green;">function</span><span style="color: Olive;">(){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">b</span><span style="color: Gray;"> = </span><span style="color: Blue;">a</span><span style="color: Gray;"> + </span><span style="color: Blue;">privateAttr</span><span style="color: Gray;">.</span><span style="color: Blue;">call</span><span style="color: Olive;">(</span><span style="color: Green;">this</span><span style="color: Gray;">, </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">c</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//访问私有属性</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">private_method</span><span style="color: Gray;">.</span><span style="color: Blue;">call</span><span style="color: Olive;">(</span><span style="color: Green;">this</span><span style="color: Olive;">)</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//访问私有方法</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">}</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">})</span><span style="color: Gray;">;&nbsp; &nbsp; </span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: #ffa500;">//工厂方法，给别人使用的接口</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">options</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">obj</span><span style="color: Gray;"> = </span><span style="color: Green;">new</span><span style="color: Gray;"> </span><span style="color: Blue;">TUI</span><span style="color: Gray;">.</span><span style="color: Blue;">dog</span><span style="color: Olive;">(</span><span style="color: Blue;">options</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">//实例加上唯一的ID，类似Ruby，注意只用+new Date()不能避免重复</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">obj</span><span style="color: Gray;">.</span><span style="color: Blue;">objectId</span><span style="color: Gray;"> = </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">tui_object</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> + </span><span style="color: Olive;">(</span><span style="color: Gray;"> +</span><span style="color: Green;">new</span><span style="color: Gray;">&nbsp;</span><span style="color: Teal;">Date</span><span style="color: Olive;">()</span><span style="color: Gray;">*</span><span style="color: Maroon;">10000</span><span style="color: Gray;"> + </span><span style="color: Teal;">Math</span><span style="color: Gray;">.</span><span style="color: Blue;">random</span><span style="color: Olive;">(</span><span style="color: Maroon;">1</span><span style="color: Olive;">)</span><span style="color: Gray;">*</span><span style="color: Maroon;">10000</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">obj</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">})(</span><span style="color: Blue;">jQuery</span><span style="color: Gray;">, </span><span style="color: Blue;">TUI</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li></ol></div>
<p>为了便于理解，以上代码是集中在一起的简单实现，进一步封装之后，有些步骤可以省略：</p>
<ul>
<li><var>objectId</var>的初始化已经由<var>TUI.clone</var>实现</li>
<li><var>privateAttr</var>方法和私有属性map由<var>TUI.newModule</var>实现</li>
<li><var>TUI.newModule</var>是<var>TUI.namespace</var>和<var>TUI.module.create</var>的封装</li>
</ul>
<h3>基于 TUI.clone 和 TUI.newModule 的写法</h3>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">TUI</span><span style="color: Gray;">.</span><span style="color: Blue;">newModule</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">TUI.widget.dog</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">sandbox</span><span style="color: Gray;">, $, </span><span style="color: Blue;">TUI</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">TUI</span><span style="color: Gray;">.</span><span style="color: Blue;">dog</span><span style="color: Gray;"> = </span><span style="color: Blue;">TUI</span><span style="color: Gray;">.</span><span style="color: Blue;">newClass</span><span style="color: Olive;">(</span><span style="color: Blue;">parentClass</span><span style="color: Gray;">, </span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">mixin</span><span style="color: Gray;">: </span><span style="color: Olive;">[</span><span style="color: Blue;">TUI</span><span style="color: Gray;">.</span><span style="color: Blue;">event</span><span style="color: Olive;">]</span><span style="color: Gray;">, </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">sandbox</span><span style="color: Gray;">: </span><span style="color: Blue;">sandbox</span><span style="color: Gray;">, </span><span style="color: #ffa500;">//有sandbox属性传入时，attr属性会被转化为外部无法访问的私有属性</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">attr</span><span style="color: Gray;">: </span><span style="color: Olive;">{</span><span style="color: Gray;">&nbsp;</span><span style="color: #ffa500;">//初始化私有属性的默认值</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">a</span><span style="color: Gray;">: </span><span style="color: Maroon;">1</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">b</span><span style="color: Gray;">: </span><span style="color: Maroon;">2</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">initialize</span><span style="color: Gray;">: </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">options</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">this</span><span style="color: Gray;">.</span><span style="color: Blue;">superClass</span><span style="color: Gray;">.</span><span style="color: Blue;">call</span><span style="color: Olive;">(</span><span style="color: Green;">this</span><span style="color: Gray;">, </span><span style="color: Blue;">arguments</span><span style="color: Olive;">)</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//访问父类构造函数</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">public_method</span><span style="color: Gray;">: </span><span style="color: Green;">function</span><span style="color: Olive;">(){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">b</span><span style="color: Gray;"> = </span><span style="color: Green;">this</span><span style="color: Gray;">.</span><span style="color: Blue;">attr</span><span style="color: Olive;">(</span><span style="color: Blue;">sandbox</span><span style="color: Gray;">, </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">a</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)</span><span style="color: Gray;"> + </span><span style="color: Green;">this</span><span style="color: Gray;">.</span><span style="color: Blue;">attr</span><span style="color: Olive;">(</span><span style="color: Blue;">sandbox</span><span style="color: Gray;">, </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">c</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//访问私有属性，通过sandbox参数来验证身份</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">}</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">})</span><span style="color: Gray;">;&nbsp; &nbsp; </span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">options</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">obj</span><span style="color: Gray;"> = </span><span style="color: Green;">new</span><span style="color: Gray;"> </span><span style="color: Blue;">TUI</span><span style="color: Gray;">.</span><span style="color: Blue;">dog</span><span style="color: Olive;">(</span><span style="color: Blue;">options</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">obj</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">}</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">jQuery</span><span style="color: Gray;">, </span><span style="color: Blue;">TUI</span><span style="color: Olive;">])</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">xiaobai</span><span style="color: Gray;"> = </span><span style="color: Blue;">TUI</span><span style="color: Gray;">.</span><span style="color: Blue;">widget</span><span style="color: Gray;">.</span><span style="color: Blue;">dog</span><span style="color: Olive;">({})</span><span style="color: Gray;">;</span></li>
<li><span style="color: Blue;">console</span><span style="color: Gray;">.</span><span style="color: Blue;">log</span><span style="color: Olive;">(</span><span style="color: Blue;">xiaobai</span><span style="color: Gray;">.</span><span style="color: Blue;">sandbox</span><span style="color: Olive;">)</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//undefined</span></li>
<li><span style="color: Blue;">console</span><span style="color: Gray;">.</span><span style="color: Blue;">log</span><span style="color: Olive;">(</span><span style="color: Blue;">xiaobai</span><span style="color: Gray;">.</span><span style="color: Blue;">attr</span><span style="color: Olive;">)</span><span style="color: Gray;">;&nbsp; &nbsp; </span><span style="color: #ffa500;">//undefined</span></li></ol></div>
<p>这里的<var>sandbox</var>其实还可以做很多事——</p>
</p></div>
<div class="section" id="sec-3">
<h2>沙盒，模块间的解耦，与外部通信</h2>
<p><var>TUI.module.create</var>方法其实来自<var>TUI.moduleClass</var>的实例，其他独立应用同样可以继承<var>TUI.moduleClass</var>，构造自己的沙盒对象</var></p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Green;">var</span><span style="color: Gray;"> </span><span style="color: Blue;">Douwan</span><span style="color: Gray;"> = </span><span style="color: Blue;">TUI</span><span style="color: Gray;">.</span><span style="color: Blue;">newClass</span><span style="color: Olive;">(</span><span style="color: Blue;">TUI</span><span style="color: Gray;">.</span><span style="color: Blue;">moduleClass</span><span style="color: Gray;">, </span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">notify</span><span style="color: Gray;">: </span><span style="color: Blue;">TUI</span><span style="color: Gray;">.</span><span style="color: Blue;">clone</span><span style="color: Olive;">(</span><span style="color: Blue;">TUI</span><span style="color: Gray;">.</span><span style="color: Blue;">event</span><span style="color: Olive;">)</span><span style="color: Gray;">, </span><span style="color: #ffa500;">//事件在这里可以理解为通信器</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">initialize</span><span style="color: Gray;">: </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">options</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">me</span><span style="color: Gray;"> = </span><span style="color: Green;">this</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">this</span><span style="color: Gray;">.</span><span style="color: Blue;">_sandbox</span><span style="color: Gray;">.</span><span style="color: Blue;">notify</span><span style="color: Gray;"> = </span><span style="color: Green;">this</span><span style="color: Gray;">.</span><span style="color: Blue;">notify</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//把通信器指向自己，避免跟全局的事件命名冲突</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">//给沙盒增加ajax方法，让module内的代码通过沙盒来通信，屏蔽url路径和响应格式之类的细节</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">url</span><span style="color: Gray;"> = </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">http://www.tudou.com/path/service.action</span><span style="color: #8b0000;">&quot;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">this</span><span style="color: Gray;">.</span><span style="color: Blue;">_sandbox</span><span style="color: Gray;">.</span><span style="color: Blue;">getJSON</span><span style="color: Gray;"> = </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">param</span><span style="color: Gray;">, </span><span style="color: Blue;">fn</span><span style="color: Olive;">){</span><span style="color: Gray;">&nbsp;</span><span style="color: #ffa500;">//模块只需要传url参数</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">me</span><span style="color: Gray;">.</span><span style="color: Blue;">getJSON</span><span style="color: Olive;">(</span><span style="color: Blue;">url</span><span style="color: Gray;">, </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">text</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">jsondata</span><span style="color: Gray;"> = </span><span style="color: Blue;">me</span><span style="color: Gray;">.</span><span style="color: Blue;">toJSON</span><span style="color: Olive;">(</span><span style="color: Blue;">text</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">fn</span><span style="color: Olive;">(</span><span style="color: Blue;">jsondata</span><span style="color: Olive;">)</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//无论返回格式是什么，都传json给模块</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">})</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">toJSON</span><span style="color: Gray;">: </span><span style="color: Green;">function</span><span style="color: Olive;">(){}</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">getJSON</span><span style="color: Gray;">: </span><span style="color: Green;">function</span><span style="color: Olive;">(){}</span></li>
<li><span style="color: Olive;">})</span><span style="color: Gray;">;</span></li></ol></div>
<p>让应用的不同模块之间解耦，避免在模块内部直接使用外部的命名（除了库的api）</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Green;">var</span><span style="color: Gray;"> </span><span style="color: Blue;">douwanObj</span><span style="color: Gray;"> = </span><span style="color: Green;">new</span><span style="color: Gray;"> </span><span style="color: Blue;">Douwan</span><span style="color: Olive;">({})</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">module1</span><span style="color: Gray;"> = </span><span style="color: Blue;">douwanObj</span><span style="color: Gray;">.</span><span style="color: Blue;">module</span><span style="color: Gray;">.</span><span style="color: Blue;">create</span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">sandbox</span><span style="color: Gray;">, $, </span><span style="color: Blue;">TUI</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">sandbox</span><span style="color: Gray;">.</span><span style="color: Blue;">getJSON</span><span style="color: Olive;">({</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">iid</span><span style="color: Gray;">: </span><span style="color: Maroon;">10000</span><span style="color: Gray;"> </span><span style="color: Olive;">}</span><span style="color: Gray;">, </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">json</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">//通过通信器调用module2.update</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">sondbox</span><span style="color: Gray;">.</span><span style="color: Blue;">notify</span><span style="color: Gray;">.</span><span style="color: Blue;">fire</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">module2-update</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">json</span><span style="color: Gray;">.</span><span style="color: Blue;">date</span><span style="color: Olive;">])</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">})</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">}</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">JQuery</span><span style="color: Gray;">, </span><span style="color: Blue;">TUI</span><span style="color: Olive;">])</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">module2</span><span style="color: Gray;"> = </span><span style="color: Blue;">douwanObj</span><span style="color: Gray;">.</span><span style="color: Blue;">module</span><span style="color: Gray;">.</span><span style="color: Blue;">create</span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">sandbox</span><span style="color: Gray;">, $, </span><span style="color: Blue;">TUI</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">obj</span><span style="color: Gray;"> = </span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">update</span><span style="color: Gray;">: </span><span style="color: Green;">function</span><span style="color: Olive;">(){}</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: #ffa500;">//注册一个update消息的接收器</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">sondbox</span><span style="color: Gray;">.</span><span style="color: Blue;">notify</span><span style="color: Gray;">.</span><span style="color: Blue;">bind</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">module2-update</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">date</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">obj</span><span style="color: Gray;">.</span><span style="color: Blue;">update</span><span style="color: Olive;">(</span><span style="color: Blue;">date</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">})</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">obj</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">}</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">JQuery</span><span style="color: Gray;">, </span><span style="color: Blue;">TUI</span><span style="color: Olive;">])</span><span style="color: Gray;">;</span></li></ol></div>
<p>页面初始化时并不一定需要渲染或操作所有模块，因此有些模块的代码可以放在外部文件里，需要的时候再注入到页面里，类似<var>Python</var>的<var>import</var></p>
</p></div>
<div class="section" id="sec-4">
<h2>按需加载模块 On-demand Lazy Load</h2>
<p>自动管理各个模块之间的依赖关系，根据代码内容加载不同的文件，这样做的成本太高，适合大型企业应用，我们的设计原则是“恰到好处”，所以通过文件名来管理模块</p>
<h3>注册模块</h3>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">TUI</span><span style="color: Gray;">.</span><span style="color: Blue;">module</span><span style="color: Gray;">.</span><span style="color: Blue;">join</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">http://js.tudouui.com/js/fn/saleloader_10.js</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Olive;">{</span><span style="color: Gray;"> </span><span style="color: Blue;">domain</span><span style="color: Gray;">: </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">http://uidev.tudou.com</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Blue;">version</span><span style="color: Gray;">: </span><span style="color: Maroon;">0</span><span style="color: Gray;"> </span><span style="color: Olive;">})</span><span style="color: Gray;">;</span></li></ol></div>
<ul>
<li>配置从url里获取，第二个配置参数是可选的，优先级更高，用于调试（指向开发环境）</li>
<li>域名其实可以省略，js文件的域名通过<var>TUI.domain</var>和autodomain.js脚本来自动配置</li>
<li>版本号很重要，支持a_10.js/a.v10.js/a_v10.js等写法</li>
</ul>
<h3>使用模块</h3>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">TUI</span><span style="color: Gray;">.</span><span style="color: Blue;">module</span><span style="color: Gray;">.</span><span style="color: Blue;">use</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">/fn/saleloader</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Green;">function</span><span style="color: Olive;">(){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">adExtension</span><span style="color: Gray;">.</span><span style="color: Blue;">load</span><span style="color: Olive;">()</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//这个是saleloader.js内的方法，必须等js加载完后执行</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: #ffa500;">//这个区域是执行saleloader.js内代码的安全空间</span></li>
<li><span style="color: Olive;">})</span><span style="color: Gray;">;</span></li></ol></div>
<ul>
<li>类似YUI3的<var>Y().use</var>，省去了版本冲突之类无用的特性</li>
<li>第一次use时会向页面里加载对应的script</li>
<li>函数区域内的代码是异步执行的，会等到saleloader.js加载完后依次执行，如果已经加载过了，直接执行，类似<var>jQuery.ready</var></li>
</ul></div>
<div class="section" id="sec-5">
<h2>总结</h2>
<ul>
<li>以上方法虽然有递进关系，但并不是要表示最后面的才是最好的方法</li>
<li>最好的方法不是唯一的，要根据场合选择最适合的方法，以上方法都有适用场合</li>
<li>本文档涉及到的API：<var>TUI.clone</var>, <var>TUI.newClass</var>, <var>TUI.moduleClass</var>, <var>TUI.module.create</var>, <var>TUI.newModule</var>, <var>TUI.module.join</var>, <var>TUI.module.use</var>, <var>TUI.event</var></li>
</ul></div>
<p>=============开始帖源码的分割线=============</p>
<h3>TUI.clone</h3>
<pre><code>
	/**
	 * @public 继承一个类或复制一个对象
	 * @note
	 * @param {object|function} oldone是需要继承的构造函数或需要复制的对象
	 * @param {object|function} ex为函数时，是子类的构造函数，或者用来加工新对象
	 * 						ex为对象时，为子类的方法, 其中initialize方法为构造函数, mixin为混入的超类
	 * @return {object|function}
	 */
	clone: function(oldone, ex){
		var newobj,
			isClass = !oldone || $.isFunction(oldone), //继承操作
			constructorFn = ex &#038;&#038; !$.isFunction(ex) &#038;&#038; ex.initialize || ex; //子类构造函数
		if (!isClass) {
			newobj = function(){
				if(constructorFn)
					constructorFn.apply(this, arguments);
			};
			newobj.prototype = oldone;
			return new newobj();
		} else {
			 //为module内部定义的类提供相关方法
			var c = { _sandbox: ex.sandbox, _default: ex.attr };
			newobj = function(){ //构造函数
				if (this.constructor === newobj) { // 如果this指向子类实例，已经执行过以下的初始化代码
					this.objectId = "TUI-object-" + ++obj_uuid; //实例的唯一ID
					var p = c;
					if (p._sandbox &#038;&#038; p._default)
						this.attr(p._sandbox, p._default); //初始化私有属性的默认值
				}
				if(constructorFn) //执行构造函数的自定义部分
					constructorFn.apply(this, arguments);
			};
			// 原型继承, 子类构造函数里需要显示调用父类构造函数
			var newproto = oldone ? this.clone(oldone.prototype) : {};
			// 混入其他超类方法
			if (ex.mixin)
				this.mix.apply(this, ([newproto]).concat(ex.mixin));
			// 加入子类方法, 覆盖混入和继承
			this.mix(newproto, ex, {
				constructor: newobj, // 恢复
				superClass: oldone || Object //在子类的构造函数中可以用this.superClass访问父类
			});
			delete newproto.initialize;
			if (c._sandbox) {
				delete newproto.sandbox; //沙盒一定要删除，不能暴露出去
				newproto.attr = function(sandbox, attrname, value){ //通过sandbox参数杜绝来自外部的访问
					return sandbox.attr.call(this, attrname, value);
				};
			}
			newobj.prototype = newproto;
			return newobj;
		}
	}

</code></pre>
<h3>TUI.moduleClass</h3>
<pre><code>
/**
 * 存放实例的私有状态
 * @private
 */
var privateAttr = {};
/**
 * module的抽象类
 * @note 可以继承到其他应用上, 构造独有的sandbox
 */
TUI.moduleClass = TUI.newClass({
	initialize: function(){
		this.notify = new TUI.eventClass();
		this._sandbox.notify = this.notify; //被继承的时候，notify可以另外指向到别处
	},
	_sandbox: {
		attr: function(name, value){ //this指向调用它的实例
			if (typeof name === "object") {
				privateAttr[this.objectId] = TUI.clone(name); //初始化私有变量的默认值
				return true;
			}
			var p = privateAttr[this.objectId];
			if (!p) //尽量在module里初始化
				p = privateAttr[this.objectId] = {};
			if (value)
				p[name] = value;
			return p[name];
		}
	},
	/**
	 * 创建一个模块，提供封闭的代码作用域和沙盒
	 * @public
	 * @param {function}
	 * @param {object} args参数
	 */
	create: function(wrap, op){
		var sandbox = TUI.clone(this._sandbox),
			args = op.args || [],
			ns = {};
		args.unshift(sandbox);
		return wrap.apply(ns, args) || ns;
	}
});

$.extend(TUI.module, new TUI.moduleClass());
</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://www.limboy.com/2009/09/20/tudou-javascript-oop-and-module-guideline/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>HTML5, CSS3, ES5&#8230;新的web标准和浏览器支持一览</title>
		<link>http://www.limboy.com/2009/06/29/html5-css3-es5-support/</link>
		<comments>http://www.limboy.com/2009/06/29/html5-css3-es5-support/#comments</comments>
		<pubDate>Mon, 29 Jun 2009 00:40:26 +0000</pubDate>
		<dc:creator>Dexter.Yy</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Firefox]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[XML]]></category>
		<category><![CDATA[web服务/应用]]></category>
		<category><![CDATA[代码]]></category>

		<guid isPermaLink="false">http://www.limboy.com/2009/06/29/html5-css3-es5-support/</guid>
		<description><![CDATA[好罢这篇本来是我私下做的笔记，我特别喜欢在Evernote上做备忘的笔记，虽然上次看到漏屋老师的文章里说我现在的年龄才刚刚进入记忆力的巅峰期……但是我的自信心仍然屡受打击！比如跟别人讨论The Dark Knight里小丑在医院对检察官说了什么让他变成双面人，我一句对白都想不起来，还有big bang theory s2里penny玩age of conan时的人物名字是&#8221;Queen Penelope&#8221;，我看的时候印象很深，一个月后就连奥德赛都想不起来了。留份笔记总觉得心里踏实些……啊又跑题了
本文整理了一些最重要（或者说人气比较高罢）的新标准，虽然它们多数还只是w3c的草案，离Recommendation级别还早，却已经成为新一轮浏览器大战中备受追捧的明星，开发者社区里也涌现出大量相关的demo和API封装，有些已经进入生产环境（比如google在iphone上实现的gmail离线应用），其实我觉得如今的web领域里，从厂商私有技术转换成委员会标准再转换成通用技术产生杀手级应用的周期已经显著的加速了，是因为现在web application的需求太高了么…… UPDATE：刚才在solidot发软文的时候我突然想明白怎么表述这个问题：其实现在很多浏览器厂商同时也是基于浏览器的应用开发者和web标准的制定者，就好像修筑舞台的工程师同时也是舞台上的演员和舞蹈动作的导演一样，所以google, mozilla, apple们都在不遗余力的实现那些有利于开发web应用的技术标准，即时它们还是W3C Working Draft，相比之下IE team就比较缺乏动力，果然计划经济缺乏活力亚XD……
由于是源自笔记，对每个条目我只会列出称呼和语法特征，暂时没时间写详细的解释和可执行的示例，但是会给出相关的文档地址，除了列出已经支持该特性的浏览器，也会为不支持的浏览器提供替代/过渡的实现。
===================废话结束的分割线=======================
CSS3 Media queries
对整个外链css文件和部分css代码使用的媒体类型侦测，人气高的原因显然是因为移动设备……
&#60;link media=“all and (orientation:portrait)” src=&#34;screen.css&#34; type=&#34;text/css&#34;&#62;
@media all and (min-color: 4) { ... }
w3c标准：http://www.w3.org/TR/css3-mediaqueries/
MDC文档：https://developer.mozilla.org/En/CSS/Media_queries
Opera文档：http://www.opera.com/docs/specs/css/
支持：Firefox 3.5+, Safari 3+, Opera 7+

CSS3 2D Transforms
css变形，有人用这个实现伪3d效果以及旋转效果的jquery插件
-moz-transform: rotate(-45deg) skew(15deg, 15deg);
sprite.style['-webkit-transform'] = 'rotate(' + v + 'rad)';
w3c标准：http://www.w3.org/TR/css3-2d-transforms/
MDC文档：https://developer.mozilla.org/En/CSS/CSS_transform_functions
webkit博客的介绍: http://webkit.org/blog/130/css-transforms/
支持：Firefox 3.5+, Safari 3.1+
替代/过渡：IE5.5+ Matrix Filter http://msdn.microsoft.com/en-us/library/ms533014(VS.85).aspx

CSS3 Transitions and [...]]]></description>
			<content:encoded><![CDATA[<p><a href='http://www.limboy.com/2009/06/29/html5-css3-es5-support/bwjpg/' rel='attachment wp-att-239' title='bw.jpg'><img src='http://www.limboy.com/wp-content/uploads/2009/06/bw.jpg' alt='bw.jpg' style="float:left;border:0;margin:0 10px 0 0;" /></a>好罢这篇本来是我私下做的笔记，我特别喜欢在<a target="_blank"  href="http://evernote.com/">Evernote</a>上做备忘的笔记，虽然上次看到<a target="_blank"  href="http://cache.tianya.cn/publicforum/content/english/1/121795.shtml">漏屋老师的文章</a>里说我现在的年龄才刚刚进入记忆力的巅峰期……但是我的自信心仍然屡受打击！比如跟别人讨论The Dark Knight里小丑在医院对检察官说了什么让他变成双面人，我一句对白都想不起来，还有big bang theory s2里penny玩age of conan时的人物名字是&#8221;Queen Penelope&#8221;，我看的时候印象很深，一个月后就连奥德赛都想不起来了。留份笔记总觉得心里踏实些……啊又跑题了</p>
<p>本文整理了一些最重要（或者说人气比较高罢）的新标准，虽然它们多数还只是w3c的草案，离Recommendation级别还早，却已经成为新一轮浏览器大战中备受追捧的明星，开发者社区里也涌现出大量相关的demo和API封装，有些已经进入生产环境（比如google在iphone上实现的<a target="_blank"  href="http://www.wired.com/epicenter/2009/02/google-turns-to/">gmail离线应用</a>），其实我觉得如今的web领域里，从厂商私有技术转换成委员会标准再转换成通用技术产生杀手级应用的周期已经显著的加速了<span id="more-238"></span>，是因为现在web application的需求太高了么…… <strong>UPDATE：</strong>刚才在solidot发软文的时候我突然想明白怎么表述这个问题：其实现在很多浏览器厂商同时也是基于浏览器的应用开发者和web标准的制定者，就好像修筑舞台的工程师同时也是舞台上的演员和舞蹈动作的导演一样，所以google, mozilla, apple们都在不遗余力的实现那些有利于开发web应用的技术标准，即时它们还是W3C Working Draft，相比之下IE team就比较缺乏动力，果然计划经济缺乏活力亚XD……</p>
<p>由于是源自笔记，对每个条目我只会列出称呼和语法特征，暂时没时间写详细的解释和可执行的示例，但是会给出相关的文档地址，除了列出已经支持该特性的浏览器，也会为不支持的浏览器提供替代/过渡的实现。</p>
<p>===================废话结束的分割线=======================</p>
<h3>CSS3 Media queries</h3>
<p>对整个外链css文件和部分css代码使用的媒体类型侦测，人气高的原因显然是因为移动设备……</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Olive;">&lt;</span><span style="color: Green;">link</span><span style="color: Gray;"> </span><span style="color: #00008b;">media</span><span style="color: Gray;">=“</span><span style="color: #00008b;">all</span><span style="color: Gray;"> </span><span style="color: #00008b;">and</span><span style="color: Gray;"> (</span><span style="color: #00008b;">orientation:portrait</span><span style="color: Gray;">)” </span><span style="color: #00008b;">src</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">screen.css</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: #00008b;">type</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">text/css</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">&gt;</span></li></ol></div>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: #00008b;">@media</span><span style="color: Gray;"> </span><span style="color: Blue;">all</span><span style="color: Gray;"> </span><span style="color: Blue;">and</span><span style="color: Gray;"> (min-color: 4) </span><span style="color: Olive;">{</span><span style="color: Gray;"> ... </span><span style="color: Olive;">}</span></li></ol></div>
<p>w3c标准：<a target="_blank"  href="http://www.w3.org/TR/css3-mediaqueries/">http://www.w3.org/TR/css3-mediaqueries/</a><br />
MDC文档：<a target="_blank"  href="https://developer.mozilla.org/En/CSS/Media_queries">https://developer.mozilla.org/En/CSS/Media_queries</a><br />
Opera文档：<a target="_blank"  href="http://www.opera.com/docs/specs/css/">http://www.opera.com/docs/specs/css/</a></p>
<p><strong style="color:#ff6600;">支持：Firefox 3.5+, Safari 3+, Opera 7+</strong><br />
<br/></p>
<h3>CSS3 2D Transforms</h3>
<p>css变形，有人用这个实现<a target="_blank"  href="http://ajaxian.com/archives/fun-with-3d-css-and-video">伪3d效果</a>以及<a target="_blank"  href="http://www.zachstronaut.com/projects/rotate3di/">旋转效果的jquery插件</a></p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Gray;">-moz-transform: </span><span style="color: Blue;">rotate</span><span style="color: Gray;">(-45</span><span style="color: Blue;">deg</span><span style="color: Gray;">) </span><span style="color: Blue;">skew</span><span style="color: Gray;">(15</span><span style="color: Blue;">deg</span><span style="color: Gray;">, 15</span><span style="color: Blue;">deg</span><span style="color: Gray;">);</span></li></ol></div>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">sprite</span><span style="color: Gray;">.</span><span style="color: Blue;">style</span><span style="color: Olive;">[</span><span style="color: #8b0000;">'</span><span style="color: Red;">-webkit-transform</span><span style="color: #8b0000;">'</span><span style="color: Olive;">]</span><span style="color: Gray;"> = </span><span style="color: #8b0000;">'</span><span style="color: Red;">rotate(</span><span style="color: #8b0000;">'</span><span style="color: Gray;"> + </span><span style="color: Blue;">v</span><span style="color: Gray;"> + </span><span style="color: #8b0000;">'</span><span style="color: Red;">rad)</span><span style="color: #8b0000;">'</span><span style="color: Gray;">;</span></li></ol></div>
<p>w3c标准：<a target="_blank"  href="http://www.w3.org/TR/css3-2d-transforms/">http://www.w3.org/TR/css3-2d-transforms/</a><br />
MDC文档：<a target="_blank"  href="https://developer.mozilla.org/En/CSS/CSS_transform_functions">https://developer.mozilla.org/En/CSS/CSS_transform_functions</a><br />
webkit博客的介绍: <a target="_blank"  href="http://webkit.org/blog/130/css-transforms/">http://webkit.org/blog/130/css-transforms/</a></p>
<p><strong style="color:#ff6600;">支持：Firefox 3.5+, Safari 3.1+</strong><br />
<strong style="color:#ff6600;">替代/过渡：IE5.5+ Matrix Filter <a target="_blank"  href="http://msdn.microsoft.com/en-us/library/ms533014(VS.85).aspx">http://msdn.microsoft.com/en-us/library/ms533014(VS.85).aspx</a></strong><br />
<br/></p>
<h3>CSS3 Transitions and CSS Animations</h3>
<p>备受期待的css动画，webkit团队提出的草案，transition实现简单的属性渐变，animation定义更复杂的动画效果</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Gray;">transition-property: </span><span style="color: Blue;">width</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">transition-duration: 1</span><span style="color: Blue;">s</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Gray;">animation-name: '</span><span style="color: Blue;">diagonal-slide</span><span style="color: Gray;">';</span></li>
<li><span style="color: Gray;">animation-duration: 5</span><span style="color: Blue;">s</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">animation-iteration-count: 10;</span></li>
<li><span style="color: #00008b;">@keyframes</span><span style="color: Gray;"> '</span><span style="color: Blue;">diagonal-slide</span><span style="color: Gray;">' </span><span style="color: Olive;">{}</span></li></ol></div>
<p>w3c标准：<a target="_blank"  href="http://www.w3.org/TR/css3-transitions/">http://www.w3.org/TR/css3-transitions/</a><br />
w3c标准：<a target="_blank"  href="http://www.w3.org/TR/css3-animations/">http://www.w3.org/TR/css3-animations/</a><br />
webkit博客的介绍：<a target="_blank"  href="http://webkit.org/blog/138/css-animation/">http://webkit.org/blog/138/css-animation/</a><br />
约翰同学的介绍：<a target="_blank"  href="http://ejohn.org/blog/css-animations-and-javascript/">http://ejohn.org/blog/css-animations-and-javascript/</a></p>
<p><strong style="color:#ff6600;">支持：Safari 3.1+</strong><br />
<br/></p>
<h3>CSS3 Downloadable fonts</h3>
<p>能在网页里嵌入任意字体是设计师的梦想……不过这里支持的也仅限truetype和opentype</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: #00008b;">@font</span><span style="color: Gray;">-</span><span style="color: Blue;">face</span><span style="color: Gray;"> </span><span style="color: Olive;">{}</span></li></ol></div>
<p>w3c标准：<a target="_blank"  href="http://www.w3.org/TR/css3-fonts/#font-resources">http://www.w3.org/TR/css3-fonts/#font-resources</a><br />
MSDN文档：<a target="_blank"  href="http://msdn.microsoft.com/en-us/library/ms530303(VS.85).aspx">http://msdn.microsoft.com/en-us/library/ms530303(VS.85).aspx</a><br />
MDC文档：<a target="_blank"  href="https://developer.mozilla.org/en/CSS/@font-face">https://developer.mozilla.org/en/CSS/@font-face</a></p>
<p><strong style="color:#ff6600;">支持：Firefox 3.5+, Safari 3.1+, Opera 10.0+, IE4.0+</strong><br />
<br/></p>
<h3>附赠：其他CSS3 property的兼容性</h3>
<p>ppk同学维护的文档: <a target="_blank"  href="http://www.quirksmode.org/css/contents.html">http://www.quirksmode.org/css/contents.html</a><br />
css3.info维护的文档：<a target="_blank"  href="http://www.css3.info/modules/selector-compat/">http://www.css3.info/modules/selector-compat/</a><br />
一个测试页面：<a target="_blank"  href="http://westciv.com/iphonetests/">http://westciv.com/iphonetests/</a><br />
<br/></p>
<h3>HTML5 DOM Storage</h3>
<p>简洁的持久存储，键值对的形式</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">window.localStorage</span></li>
<li><span style="color: Blue;">window.sessionStorage</span><span style="color: Gray;"> //可跨域，标签页关掉就清空</span></li></ol></div>
<p>w3c标准：<a target="_blank"  href="http://www.w3.org/TR/webstorage/">http://www.w3.org/TR/webstorage/</a><br />
ppk同学维护的兼容性列表：<a target="_blank"  href="http://www.quirksmode.org/dom/html5.html#localstorage">http://www.quirksmode.org/dom/html5.html#localstorage</a><br />
MDC文档：<a target="_blank"  href="https://developer.mozilla.org/en/DOM/Storage">https://developer.mozilla.org/en/DOM/Storage</a><br />
MSDN文档：<a target="_blank"  href="http://msdn.microsoft.com/en-us/library/cc197062(VS.85).aspx">http://msdn.microsoft.com/en-us/library/cc197062(VS.85).aspx</a></p>
<p><strong style="color:#ff6600;">支持：Firefox 3.5+, Safari 4.0+, IE 8.0+</strong><br />
<br/></p>
<h3>HTML5 Offline Application Cache</h3>
<p>用一个manifest文件缓存静态资源（图片,css, js之类）在离线状态下使用，不是结构化数据</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Olive;">&lt;</span><span style="color: Green;">html</span><span style="color: Gray;"> </span><span style="color: #00008b;">manifest</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">foo.manifest</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">&gt;</span></li></ol></div>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">CACHE MANIFEST</li>
<li>index.html</li>
<li>style/default.css</li>
<li>images/logo.png</li></ol></div>
<p>w3c标准：<a target="_blank"  href="http://www.w3.org/TR/offline-webapps/#offline">http://www.w3.org/TR/offline-webapps/#offline</a><br />
MDC文档：<a target="_blank"  href="https://developer.mozilla.org/en/Offline_resources_in_Firefox">https://developer.mozilla.org/en/Offline_resources_in_Firefox</a></p>
<p><strong style="color:#ff6600;">支持：Firefox 3.5+</strong><br />
<br/></p>
<h3>HTML5 Database Storage</h3>
<p>本地数据库，支持sql，最早是google gears实现，现在的w3c草案的编辑也是google的工程师……但奇怪的是，gears的api跟现在的草案不兼容，chrome甚至为了保留捆绑的gears的数据库api而删除了webkit实现的html5 api……而google在iphone上实现gmail离线功能的时候又采用webkit的api……真纠结……</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Green;">var</span><span style="color: Gray;"> </span><span style="color: Blue;">db</span><span style="color: Gray;"> = </span><span style="color: Teal;">window</span><span style="color: Gray;">.</span><span style="color: Blue;">openDatabase</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">notes</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: #8b0000;">&quot;&quot;</span><span style="color: Gray;">, </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">The Example Notes App!</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Maroon;">1048576</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Blue;">db</span><span style="color: Gray;">.</span><span style="color: Blue;">transaction</span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">tx</span><span style="color: Olive;">)</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">{</span></li>
<li><span style="color: Blue;">tx</span><span style="color: Gray;">.</span><span style="color: Blue;">executeSql</span><span style="color: Olive;">(</span><span style="color: Gray;">‘</span><span style="color: Blue;">SELECT</span><span style="color: Gray;"> * </span><span style="color: Blue;">FROM</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">Notes</span><span style="color: Gray;">’, </span><span style="color: Olive;">[]</span><span style="color: Gray;">, </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">tx</span><span style="color: Gray;">, </span><span style="color: Blue;">rs</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Olive;">{})</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">})</span><span style="color: Gray;">;</span></li></ol></div>
<p>w3c标准：<a target="_blank"  href="http://www.w3.org/TR/offline-webapps/#sql">http://www.w3.org/TR/offline-webapps/#sql</a><br />
webkit博客的介绍：<a target="_blank"  href="http://webkit.org/blog/126/webkit-does-html5-client-side-database-storage/">http://webkit.org/blog/126/webkit-does-html5-client-side-database-storage/</a><br />
iphone的文档：<a target="_blank"  href="http://developer.apple.com/documentation/iPhone/Conceptual/SafariJSDatabaseGuide/UsingtheJavascriptDatabase/UsingtheJavascriptDatabase.html#//apple_ref/doc/uid/TP40007256-CH3-SW1">http://developer.apple.com/documentation/iPhone/Conceptual/SafariJSDatabaseGuide/UsingtheJavascriptDatabase/UsingtheJavascriptDatabase.html#//apple_ref/doc/uid/TP40007256-CH3-SW1</a></p>
<p><strong style="color:#ff6600;">支持：Safari 3.1+</strong><br />
<strong style="color:#ff6600;">替代/过渡：Gears <a target="_blank"  href="http://code.google.com/p/gears/wiki/Database2API">http://code.google.com/p/gears/wiki/Database2API</a></strong><br />
<br/></p>
<h3>HTML5 Web Workers</h3>
<p>多线程，在后台执行复杂运算，不能操作dom，线程之间通过消息事件通信</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Green;">var</span><span style="color: Gray;"> </span><span style="color: Blue;">myWorker</span><span style="color: Gray;"> = </span><span style="color: Green;">new</span><span style="color: Gray;"> </span><span style="color: Blue;">Worker</span><span style="color: Olive;">(</span><span style="color: #8b0000;">'</span><span style="color: Red;">my_worker.js</span><span style="color: #8b0000;">'</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Blue;">myWorker</span><span style="color: Gray;">.</span><span style="color: Blue;">onmessage</span><span style="color: Gray;"> = </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">event</span><span style="color: Olive;">)</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">{</span><span style="color: Gray;"> </span><span style="color: Blue;">event</span><span style="color: Gray;">.</span><span style="color: Blue;">data</span><span style="color: Gray;"> </span><span style="color: Olive;">}</span><span style="color: Gray;">;</span></li>
<li><span style="color: Blue;">myWorker</span><span style="color: Gray;">.</span><span style="color: Blue;">postMessage</span><span style="color: Olive;">(</span><span style="color: Blue;">str</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li></ol></div>
<p>w3c标准：<a target="_blank"  href="http://www.w3.org/TR/workers/">http://www.w3.org/TR/workers/</a><br />
MDC文档：<a target="_blank"  href="https://developer.mozilla.org/En/Using_web_workers">https://developer.mozilla.org/En/Using_web_workers</a></p>
<p><strong style="color:#ff6600;">支持：Firefox 3.5+</strong><br />
<strong style="color:#ff6600;">替代/过渡：Gears <a target="_blank"  href="http://code.google.com/p/gears/wiki/HTML5WorkerProposal">http://code.google.com/p/gears/wiki/HTML5WorkerProposal</a></strong><br />
<br/></p>
<h3>HTML5 Geolocation</h3>
<p>地理api</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Teal;">window</span><span style="color: Gray;">.</span><span style="color: Teal;">navigator</span><span style="color: Gray;">.</span><span style="color: Blue;">geolocation</span></li></ol></div>
<p>w3c标准：<a target="_blank"  href="http://www.w3.org/TR/geolocation-API/">http://www.w3.org/TR/geolocation-API/</a><br />
MDC文档：<a target="_blank"  href="https://developer.mozilla.org/En/Using_geolocation">https://developer.mozilla.org/En/Using_geolocation</a></p>
<p><strong style="color:#ff6600;">支持：Firefox 3.5+</strong><br />
<strong style="color:#ff6600;">替代/过渡：Gears <a target="_blank"  href="http://code.google.com/p/gears/wiki/GeolocationAPI">http://code.google.com/p/gears/wiki/GeolocationAPI</a></strong><br />
<br/></p>
<h3>HTML5 Drag and Drop</h3>
<p>原生拖拽事件</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">ondragstart</span></li>
<li><span style="color: Blue;">ondrag</span></li>
<li><span style="color: Blue;">ondragend</span></li>
<li><span style="color: #ffa500;">//拖拽过程中</span></li>
<li><span style="color: Blue;">ondragenter</span></li>
<li><span style="color: Blue;">ondragover</span></li>
<li><span style="color: Blue;">ondragleave</span></li>
<li><span style="color: Blue;">ondrop</span></li></ol></div>
<p>w3c标准：<a target="_blank"  href="http://www.w3.org/TR/html5/editing.html#dnd">http://www.w3.org/TR/html5/editing.html#dnd</a><br />
MDC文档：<a target="_blank"  href="https://developer.mozilla.org/En/DragDrop/Drag_and_Drop">https://developer.mozilla.org/En/DragDrop/Drag_and_Drop</a><br />
apple文档：<a target="_blank"  href="http://developer.apple.com/documentation/AppleApplications/Conceptual/SafariJSProgTopics/Tasks/DragAndDrop.html#//apple_ref/doc/uid/30001233">http://developer.apple.com/documentation/AppleApplications/Conceptual/SafariJSProgTopics/Tasks/DragAndDrop.html#//apple_ref/doc/uid/30001233</a></p>
<p><strong style="color:#ff6600;">支持：Firefox 3.5+, Safari 2.0+, Chrome 1.0+, IE 5.0+</strong><br />
<br/></p>
<h3>HTML5 Audio and Video</h3>
<p>用html标签来嵌入视频音频的好处并非是“开源格式”，而是“开放性”，让多媒体可以与其他页面元素交互，或者<a target="_blank"  href="http://blog.mozbox.org/post/2009/04/12/Firefox-35:-a-new-experiment-with-Canvas-Video">用页面技术去跟视频“mashup”</a>，这种随意组合和交互的能力是web技术兴盛的基石，也是像flash这类封闭RIA容器最大的缺点。</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Olive;">&lt;</span><span style="color: Green;">video</span><span style="color: Gray;"> </span><span style="color: #00008b;">controls</span><span style="color: Olive;">&gt;</span></li>
<li><span style="color: Olive;">&lt;</span><span style="color: Green;">source</span><span style="color: Gray;">&nbsp;</span><span style="color: #00008b;">src</span><span style="color: Gray;">=“</span><span style="color: #00008b;">zombie</span><span style="color: Gray;">.</span><span style="color: #00008b;">ogg</span><span style="color: Gray;">” </span><span style="color: #00008b;">type</span><span style="color: Gray;">=“</span><span style="color: #00008b;">video</span><span style="color: Gray;">/</span><span style="color: Green;">ogg</span><span style="color: Gray;">”</span><span style="color: Olive;">/&gt;</span></li>
<li><span style="color: Olive;">&lt;</span><span style="color: Green;">source</span><span style="color: Gray;">&nbsp;</span><span style="color: #00008b;">src</span><span style="color: Gray;">=“</span><span style="color: #00008b;">zombie</span><span style="color: Gray;">.</span><span style="color: #00008b;">mp4</span><span style="color: Gray;">″ </span><span style="color: #00008b;">type</span><span style="color: Gray;">=“</span><span style="color: #00008b;">video</span><span style="color: Gray;">/</span><span style="color: Green;">mp4</span><span style="color: Gray;">″</span><span style="color: Olive;">/&gt;</span></li>
<li><span style="color: Olive;">&lt;/</span><span style="color: Green;">video</span><span style="color: Olive;">&gt;</span></li></ol></div>
<p>MDC文档：<a target="_blank"  href="https://developer.mozilla.org/En/Using_audio_and_video_in_Firefox">https://developer.mozilla.org/En/Using_audio_and_video_in_Firefox</a><br />
webkit博客的介绍：<a target="_blank"  href="http://webkit.org/blog/140/html5-media-support/">http://webkit.org/blog/140/html5-media-support/</a></p>
<p><strong style="color:#ff6600;">支持：Firefox 3.5+, Safari 3.0+, Chrome 3.0+</strong><br />
<strong style="color:#ff6600;">替代/过渡：用video标签嵌套embed <a target="_blank"  href="http://hacks.mozilla.org/2009/06/html5-video-fallbacks-markup/">http://hacks.mozilla.org/2009/06/html5-video-fallbacks-markup/</a></strong><br />
<br/></p>
<h3>HTML5 Canvas</h3>
<p>apple发明，最早应用于dashboard，目前主流的js图像技术，mozilla已经在实现OpenGL ES标准的<a target="_blank"  href="http://blog.vlad1.com/2007/11/26/canvas-3d-gl-power-web-style/">Canvas 3D</a>了，另外据说ie team为支持canvas<a target="_blank"  href="http://processingjs.org/blog/?p=77">做了大量工作</a>……实际上canvas api相当底层，特别是交互方面，不如svg直观，所以出现了很多封装它的库</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Green;">var</span><span style="color: Gray;"> </span><span style="color: Blue;">ctx</span><span style="color: Gray;"> = $</span><span style="color: Olive;">(</span><span style="color: #8b0000;">'</span><span style="color: Red;">#canvas</span><span style="color: #8b0000;">'</span><span style="color: Olive;">)[</span><span style="color: Maroon;">0</span><span style="color: Olive;">]</span><span style="color: Gray;">.</span><span style="color: Blue;">getContext</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">2d</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Blue;">ctx</span><span style="color: Gray;">.</span><span style="color: Blue;">fillStyle</span><span style="color: Gray;"> = </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">#00A308</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">;</span></li>
<li><span style="color: Blue;">ctx</span><span style="color: Gray;">.</span><span style="color: Blue;">beginPath</span><span style="color: Olive;">()</span><span style="color: Gray;">;</span></li>
<li><span style="color: Blue;">ctx</span><span style="color: Gray;">.</span><span style="color: Blue;">arc</span><span style="color: Olive;">(</span><span style="color: Maroon;">220</span><span style="color: Gray;">, </span><span style="color: Maroon;">220</span><span style="color: Gray;">, </span><span style="color: Maroon;">50</span><span style="color: Gray;">, </span><span style="color: Maroon;">0</span><span style="color: Gray;">, </span><span style="color: Teal;">Math</span><span style="color: Gray;">.</span><span style="color: Blue;">PI</span><span style="color: Gray;">*</span><span style="color: Maroon;">2</span><span style="color: Gray;">, </span><span style="color: Green;">true</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Blue;">ctx</span><span style="color: Gray;">.</span><span style="color: Blue;">closePath</span><span style="color: Olive;">()</span><span style="color: Gray;">;</span></li>
<li><span style="color: Blue;">ctx</span><span style="color: Gray;">.</span><span style="color: Blue;">fill</span><span style="color: Olive;">()</span><span style="color: Gray;">;</span></li></ol></div>
<p>MDC文档：<a target="_blank"  href="https://developer.mozilla.org/en/Canvas_tutorial">https://developer.mozilla.org/en/Canvas_tutorial</a></p>
<p><strong style="color:#ff6600;">支持：Firefox 1.5+, Safari 2.0+, Chrome 1.0+, Opera 9.0+</strong><br />
<strong style="color:#ff6600;">替代/过渡：excanvas.js <a target="_blank"  href="http://code.google.com/p/explorercanvas/">http://code.google.com/p/explorercanvas/</a></strong><br />
<br/></p>
<h3>SVG</h3>
<p>w3c标准：<a target="_blank"  href="http://www.w3.org/TR/SVG12/">http://www.w3.org/TR/SVG12/</a><br />
IBM DW教程：<a target="_blank"  href="http://www.ibm.com/developerworks/cn/views/xml/tutorials.jsp?cv_doc_id=84896">http://www.ibm.com/developerworks/cn/views/xml/tutorials.jsp?cv_doc_id=84896</a></p>
<p><strong style="color:#ff6600;">支持：Firefox 1.5+, Safari 3.0+, Chrome 1.0+, Opera 9.0+</strong><br />
<strong style="color:#ff6600;">替代/过渡：raphael.js <a target="_blank"  href="http://raphaeljs.com/">http://raphaeljs.com/</a></strong><br />
<br/></p>
<h3>XMLHttpRequest 2</h3>
<p>主要是增加跨域能力以及请求过程中的事件</p>
<p>w3c标准：<a target="_blank"  href="http://www.w3.org/TR/XMLHttpRequest2/">http://www.w3.org/TR/XMLHttpRequest2/</a><br />
MDC文档：<a target="_blank"  href="https://developer.mozilla.org/En/Using_XMLHttpRequest#Monitoring_progress">https://developer.mozilla.org/En/Using_XMLHttpRequest#Monitoring_progress</a><br />
XDomainRequest (XDR)<br />
MSDN文档：<a target="_blank"  href="http://msdn.microsoft.com/en-us/library/cc288060(VS.85).aspx">http://msdn.microsoft.com/en-us/library/cc288060(VS.85).aspx</a></p>
<p><strong style="color:#ff6600;">支持：Firefox 3.5+（实现了部分）, IE 8.0+（实现了部分）</strong><br />
<br/></p>
<h3>Access Control</h3>
<p>千呼万唤的跨域访问控制，目前firefox3.5和ie8有一些不同，ie8搞的XDR和XDM我也不知道是不是准备提交给w3c标准化的东西……</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">Access-Control-Allow-Origin: http://foo.example</li></ol></div>
<p>w3c标准：<a target="_blank"  href="http://www.w3.org/TR/cors/">http://www.w3.org/TR/cors/</a><br />
MDC文档：<a target="_blank"  href="https://developer.mozilla.org/En/HTTP_Access_Control">https://developer.mozilla.org/En/HTTP_Access_Control</a><br />
Cross-document Messaging (XDM)<br />
MSDN文档：<a target="_blank"  href="http://msdn.microsoft.com/en-us/library/cc197057(VS.85).aspx">http://msdn.microsoft.com/en-us/library/cc197057(VS.85).aspx</a></p>
<p><strong style="color:#ff6600;">支持：Firefox 3.5+, IE8.0+</strong><br />
<br/></p>
<h3>E4X (ECMA-357)</h3>
<p>Firefox和ActionScript3早就实现了的东西……不过其实现在json这么流行，有没有E4X好像都无所谓了～（瞎说的，其实在js代码里直接写dom对象而不是html字符串，会方便很多）</p>
<p>MDC文档：<a target="_blank"  href="https://developer.mozilla.org/en/E4X">https://developer.mozilla.org/en/E4X</a></p>
<p><strong style="color:#ff6600;">支持：Firefox 1.5+</strong><br />
<br/></p>
<h3>ECMAScript 5  Native JSON</h3>
<p>原生的JSON支持，速度和安全性都比eval强一百倍亚一百倍，另外要注意Douglas Crockford的json2.js是一个用js实现的js解释器，所以安全性更好</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">JSON</span><span style="color: Gray;">.</span><span style="color: Blue;">parse</span><span style="color: Olive;">(</span><span style="color: Gray;"> </span><span style="color: Blue;">text</span><span style="color: Gray;">, </span><span style="color: Blue;">translate</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span></li>
<li><span style="color: Blue;">JSON</span><span style="color: Gray;">.</span><span style="color: Blue;">stringify</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">obj</span><span style="color: Gray;">, </span><span style="color: Blue;">translate</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span></li>
<li><span style="color: Teal;">String</span><span style="color: Gray;">.</span><span style="color: Blue;">prototype</span><span style="color: Gray;">.</span><span style="color: Blue;">toJSON</span></li>
<li><span style="color: Blue;">Boolean</span><span style="color: Gray;">.</span><span style="color: Blue;">prototype</span><span style="color: Gray;">.</span><span style="color: Blue;">toJSON</span></li>
<li><span style="color: Teal;">Number</span><span style="color: Gray;">.</span><span style="color: Blue;">prototype</span><span style="color: Gray;">.</span><span style="color: Blue;">toJSON</span></li>
<li><span style="color: Teal;">Date</span><span style="color: Gray;">.</span><span style="color: Blue;">prototype</span><span style="color: Gray;">.</span><span style="color: Blue;">toJSON</span></li></ol></div>
<p>MDC文档：<a target="_blank"  href="http://blog.mozilla.com/webdev/2009/02/12/native-json-in-firefox-31/">http://blog.mozilla.com/webdev/2009/02/12/native-json-in-firefox-31/</a><br />
MSDN文档：<a target="_blank"  href="http://blogs.msdn.com/ie/archive/2008/09/10/native-json-in-ie8.aspx">http://blogs.msdn.com/ie/archive/2008/09/10/native-json-in-ie8.aspx</a></p>
<p><strong style="color:#ff6600;">支持：Firefox 3.5+, IE8+</strong><br />
<strong style="color:#ff6600;">替代/过渡：json2.js <a target="_blank"  href="http://www.json.org/json2.js">http://www.json.org/json2.js</a></strong><br />
<br/></p>
<h3>ECMAScript 5  Array Extras</h3>
<p>js1.6里实现的数组方法，主要是forEach, map, fliter这几个函数式编程里非常重要的方法，还有反向查询</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Teal;">Array</span><span style="color: Gray;">.</span><span style="color: Blue;">prototype</span><span style="color: Gray;">.</span><span style="color: Blue;">indexOf</span><span style="color: Olive;">(</span><span style="color: Gray;"> </span><span style="color: Blue;">str</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span></li>
<li><span style="color: Teal;">Array</span><span style="color: Gray;">.</span><span style="color: Blue;">prototype</span><span style="color: Gray;">.</span><span style="color: Blue;">lastIndexOf</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">str</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span></li>
<li><span style="color: Teal;">Array</span><span style="color: Gray;">.</span><span style="color: Blue;">prototype</span><span style="color: Gray;">.</span><span style="color: Blue;">every</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">fn</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span></li>
<li><span style="color: Teal;">Array</span><span style="color: Gray;">.</span><span style="color: Blue;">prototype</span><span style="color: Gray;">.</span><span style="color: Blue;">some</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">fn</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span></li>
<li><span style="color: Teal;">Array</span><span style="color: Gray;">.</span><span style="color: Blue;">prototype</span><span style="color: Gray;">.</span><span style="color: Blue;">filter</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">fn</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span></li>
<li><span style="color: Teal;">Array</span><span style="color: Gray;">.</span><span style="color: Blue;">prototype</span><span style="color: Gray;">.</span><span style="color: Blue;">forEach</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">fn</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span></li>
<li><span style="color: Teal;">Array</span><span style="color: Gray;">.</span><span style="color: Blue;">prototype</span><span style="color: Gray;">.</span><span style="color: Blue;">map</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">fn</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span></li></ol></div>
<p>MDC文档：<a target="_blank"  href="https://developer.mozilla.org/en/New_in_JavaScript_1.6#Array_extras">https://developer.mozilla.org/en/New_in_JavaScript_1.6#Array_extras</a></p>
<p><strong style="color:#ff6600;">支持：Firefox2.0+, Safari 3.0+, Google Chrome 1.0+, Opera 9.5+</strong><br />
<strong style="color:#ff6600;">替代/过渡：都可以通过扩展Array.prototype来模拟</strong><br />
<br/></p>
<h3>ECMAScript 5  isArray()</h3>
<p>区分数组和对象</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Teal;">Array</span><span style="color: Gray;">.</span><span style="color: Blue;">isArray</span><span style="color: Olive;">([])</span><span style="color: Gray;">; </span><span style="color: #ffa500;">// true</span></li></ol></div>
<p><strong style="color:#ff6600;">支持：无</strong><br />
<strong style="color:#ff6600;">替代/过渡：Array.isArray = function(a){ return Object.prototype.toString.call(a) === &#8220;[object Array]&#8220;;};</strong><br />
<br/></p>
<h3>ECMAScript 5  Object</h3>
<p>用GOOGLE I/O演讲里的话来说：更鲁棒(robust)的对象系统<br />
<br/></p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">Object</span><span style="color: Gray;">.</span><span style="color: Blue;">getPrototypeOf</span><span style="color: Olive;">(</span><span style="color: Gray;"> </span><span style="color: Blue;">obj</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span></li></ol></div>
<p>约翰同学的讲解：<a target="_blank"  href="http://ejohn.org/blog/objectgetprototypeof/">http://ejohn.org/blog/objectgetprototypeof/</a></p>
<p><strong style="color:#ff6600;">支持：Firefox3.5</strong><br />
<strong style="color:#ff6600;">替代/过渡：object.__proto__ 或 object.constructor.prototype</strong><br />
<br/></p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">Object</span><span style="color: Gray;">.</span><span style="color: Blue;">create</span><span style="color: Olive;">(</span><span style="color: Gray;"> </span><span style="color: Blue;">proto</span><span style="color: Gray;">, </span><span style="color: Blue;">props</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: #ffa500;">//克隆或继承对象</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Blue;">Object</span><span style="color: Gray;">.</span><span style="color: Blue;">keys</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">obj</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: #ffa500;">//数据结构的映射</span></li>
<li><span style="color: Blue;">Object</span><span style="color: Gray;">.</span><span style="color: Blue;">getOwnPropertyNames</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">obj</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Blue;">Object</span><span style="color: Gray;">.</span><span style="color: Blue;">preventExtensions</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">obj</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: #ffa500;">//不能添加新属性</span></li>
<li><span style="color: Blue;">Object</span><span style="color: Gray;">.</span><span style="color: Blue;">isExtensible</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">obj</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Blue;">Object</span><span style="color: Gray;">.</span><span style="color: Blue;">seal</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">obj</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: #ffa500;">//不能删除和修改属性的配置，不能添加新属性</span></li>
<li><span style="color: Blue;">Object</span><span style="color: Gray;">.</span><span style="color: Blue;">isSealed</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">obj</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Blue;">Object</span><span style="color: Gray;">.</span><span style="color: Blue;">freeze</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">obj</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: #ffa500;">//不能删除和修改属性的配置，不能添加新属性，不能写属性</span></li>
<li><span style="color: Blue;">Object</span><span style="color: Gray;">.</span><span style="color: Blue;">isFrozen</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">obj</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span></li></ol></div>
<p>约翰同学的讲解：<a target="_blank"  href="http://ejohn.org/blog/ecmascript-5-objects-and-properties/">http://ejohn.org/blog/ecmascript-5-objects-and-properties/</a></p>
<p><strong style="color:#ff6600;">支持：无</strong><br />
<strong style="color:#ff6600;">替代/过渡：Object.create和Object.keys可以自己实现</strong><br />
<br/></p>
<h3>ECMAScript 5 Property Descriptor</h3>
<p>对象属性的访问控制</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">Object</span><span style="color: Gray;">.</span><span style="color: Blue;">getOwnPropertyDescriptor</span><span style="color: Olive;">(</span><span style="color: Gray;"> </span><span style="color: Blue;">obj</span><span style="color: Gray;">, </span><span style="color: Blue;">prop</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span></li>
<li><span style="color: Blue;">Object</span><span style="color: Gray;">.</span><span style="color: Blue;">defineProperty</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">obj</span><span style="color: Gray;">, </span><span style="color: Blue;">prop</span><span style="color: Gray;">, </span><span style="color: Blue;">desc</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span></li>
<li><span style="color: Blue;">Object</span><span style="color: Gray;">.</span><span style="color: Blue;">defineProperties</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">obj</span><span style="color: Gray;">, </span><span style="color: Blue;">props</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Blue;">desc</span><span style="color: Gray;"> = </span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp;&nbsp; </span><span style="color: Blue;">value</span><span style="color: Gray;">: </span><span style="color: Green;">true</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp;&nbsp; </span><span style="color: Blue;">writable</span><span style="color: Gray;">: </span><span style="color: Green;">false</span><span style="color: Gray;">, </span><span style="color: #ffa500;">//修改</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp;&nbsp; </span><span style="color: Blue;">enumerable</span><span style="color: Gray;">: </span><span style="color: Green;">true</span><span style="color: Gray;">, </span><span style="color: #ffa500;">//for in</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp;&nbsp; </span><span style="color: Blue;">configurable</span><span style="color: Gray;">: </span><span style="color: Green;">true</span><span style="color: Gray;">, </span><span style="color: #ffa500;">//删除和修改属性</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp;&nbsp; </span><span style="color: Blue;">get</span><span style="color: Gray;">: </span><span style="color: Green;">function</span><span style="color: Olive;">(){</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">return</span><span style="color: Gray;"> </span><span style="color: Blue;">name</span><span style="color: Gray;">; </span><span style="color: Olive;">}</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp;&nbsp; </span><span style="color: Blue;">set</span><span style="color: Gray;">: </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">value</span><span style="color: Olive;">){</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">name</span><span style="color: Gray;"> = </span><span style="color: Blue;">value</span><span style="color: Gray;">; </span><span style="color: Olive;">}</span></li>
<li><span style="color: Olive;">}</span></li></ol></div>
<p>约翰同学的讲解：<a target="_blank"  href="http://ejohn.org/blog/ecmascript-5-objects-and-properties/">http://ejohn.org/blog/ecmascript-5-objects-and-properties/</a></p>
<p><strong style="color:#ff6600;">支持：无</strong><br />
<strong style="color:#ff6600;">替代/过渡：Object.defineProperties其实相当于jQuery.extend，用来实现Mixin</strong><br />
<br/></p>
<h3>ECMAScript 5 Getters and Setters</h3>
<p>python和ruby里都有的属性访问方法</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">obj</span><span style="color: Gray;"> = </span><span style="color: Olive;">{</span><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Gray;">&nbsp;&nbsp; </span><span style="color: Blue;">get</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">innerHTML</span><span style="color: Olive;">()</span><span style="color: Gray;"> </span><span style="color: Olive;">{</span><span style="color: Gray;"> </span><span style="color: Green;">return</span><span style="color: Gray;"> …; </span><span style="color: Olive;">}</span><span style="color: Gray;">, </span></li>
<li><span style="color: Gray;">&nbsp;&nbsp; </span><span style="color: Blue;">set</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">innerHTML</span><span style="color: Olive;">(</span><span style="color: Blue;">newHTML</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Olive;">{</span><span style="color: Gray;"> … </span><span style="color: Olive;">}</span><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Olive;">}</span><span style="color: Gray;">;</span></li></ol></div>
<p>MDC文档：<a target="_blank"  href="https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Creating_New_Objects/Defining_Getters_and_Setters">https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Creating_New_Objects/Defining_Getters_and_Setters</a></p>
<p><strong style="color:#ff6600;">支持：Firefox 2.0+, Safari 3.0+, Google Chrome 1.0+, Opera 9.5+</strong><br />
<strong style="color:#ff6600;">替代/过渡：</strong></p>
<p>非标准，Firefox1.5里的旧方法</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">HTMLElement</span><span style="color: Gray;">.</span><span style="color: Blue;">prototype</span><span style="color: Gray;">.</span><span style="color: Blue;">__defineGetter__</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">innerHTML</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Green;">function</span><span style="color: Gray;"> </span><span style="color: Olive;">()</span><span style="color: Gray;"> </span><span style="color: Olive;">{})</span><span style="color: Gray;">;</span></li>
<li><span style="color: Blue;">HTMLElement</span><span style="color: Gray;">.</span><span style="color: Blue;">prototype</span><span style="color: Gray;">.</span><span style="color: Blue;">__defineSetter__</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">innerHTML</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Green;">function</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">(</span><span style="color: Blue;">val</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Olive;">{})</span><span style="color: Gray;">;</span></li></ol></div>
<p><strong style="color:#ff6600;">支持：Firefox 2.0+, Safari 3.0+, Google Chrome 1.0+, Opera 9.5+</strong></p>
<p>标准</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">Object</span><span style="color: Gray;">.</span><span style="color: Blue;">defineProperty</span><span style="color: Olive;">(</span><span style="color: Teal;">document</span><span style="color: Gray;">.</span><span style="color: Blue;">body</span><span style="color: Gray;">, </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">innerHTML</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Olive;">{</span><span style="color: Gray;"> </span><span style="color: Blue;">get</span><span style="color: Gray;"> : </span><span style="color: Green;">function</span><span style="color: Gray;"> </span><span style="color: Olive;">()</span><span style="color: Gray;"> </span><span style="color: Olive;">{}</span><span style="color: Gray;"> </span><span style="color: Olive;">})</span><span style="color: Gray;">;</span></li></ol></div>
<p>MSDN文档：<a target="_blank"  href="http://msdn.microsoft.com/en-us/library/dd229916(VS.85).aspx">http://msdn.microsoft.com/en-us/library/dd229916(VS.85).aspx</a></p>
<p><strong style="color:#ff6600;">支持：IE8+ (只能对DOM使用)</strong><br />
<br/></p>
<h3>ECMAScript 5 Strict Mode</h3>
<p>ES5的严格模式，删除了旧版本中容易引起问题的元素，并且会显式的报错，方便调试</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: #8b0000;">&quot;</span><span style="color: Red;">use strict</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//以下情况下抛出异常</span></li>
<li><span style="color: #ffa500;">//对未定义的变量赋值</span></li>
<li><span style="color: #ffa500;">//操作被设置为不可写，不可配置或不可扩充的属性</span></li>
<li><span style="color: #ffa500;">//删除变量，函数，参数</span></li>
<li><span style="color: #ffa500;">//在对象直接量里重复定义属性</span></li>
<li><span style="color: #ffa500;">//eval做关键字，在eval的字符串里定义变量</span></li>
<li><span style="color: #ffa500;">//覆写arguments</span></li>
<li><span style="color: #ffa500;">//使用arguments.caller和arguments.callee（匿名函数必须具名才能引用自己）</span></li>
<li><span style="color: #ffa500;">//(function(){ ... }).call( null ); // Exception </span></li>
<li><span style="color: #ffa500;">//使用with</span></li></ol></div>
<p>约翰同学的讲解：<a target="_blank"  href="http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/">http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/</a></p>
<p><strong style="color:#ff6600;">支持：无</strong><br />
<strong style="color:#ff6600;">替代/过渡：……从现在开始养成严谨的编程习惯</strong><br />
<br/></p>
<h3>ECMAScript 5 其他新特性</h3>
<p>传递函数的引用时，绑定this</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Teal;">Function</span><span style="color: Gray;">.</span><span style="color: Blue;">prototype</span><span style="color: Gray;">.</span><span style="color: Blue;">bind</span><span style="color: Olive;">(</span><span style="color: Blue;">thisArg</span><span style="color: Gray;">, </span><span style="color: Blue;">arg1</span><span style="color: Gray;">, </span><span style="color: Blue;">arg2</span><span style="color: Gray;">....</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: #8b0000;">/</span></li></ol></div>
<p><strong style="color:#ff6600;">支持：无</strong><br />
<strong style="color:#ff6600;">替代/过渡：prototype <a target="_blank"  href="http://www.prototypejs.org/api/function/bind">http://www.prototypejs.org/api/function/bind</a></strong></p>
<p>ISO-formatted dates</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Teal;">Date</span><span style="color: Gray;">.</span><span style="color: Blue;">prototype</span><span style="color: Gray;">.</span><span style="color: Blue;">toISOString</span><span style="color: Olive;">()</span><span style="color: Gray;"> </span><span style="color: #ffa500;">// Prints 2009-05-21T16:06:05.000TZ</span></li></ol></div>
<p><strong style="color:#ff6600;">支持：无</strong><br />
<strong style="color:#ff6600;">替代/过渡：datejs <a target="_blank"  href="http://code.google.com/p/datejs/">http://code.google.com/p/datejs/</a></strong></p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Teal;">String</span><span style="color: Gray;">.</span><span style="color: Blue;">prototype</span><span style="color: Gray;">.</span><span style="color: Blue;">trim</span><span style="color: Olive;">()</span></li></ol></div>
<p><strong style="color:#ff6600;">支持：Firefox3.5</strong><br />
<strong style="color:#ff6600;">替代/过渡：各种正则实现 <a target="_blank"  href="http://blog.stevenlevithan.com/archives/faster-trim-javascript">http://blog.stevenlevithan.com/archives/faster-trim-javascript</a></strong><br />
<br/><br />
===================废话又开始的分割线=======================</p>
<p>其实我把这个东西发出来是希望能促进创新的氛围，让更多人认识到很多新技术已经进入到“实用”阶段。</p>
<p>如果只是想做个实验性的webgame，或是只能用于特定平台的应用（比如iphone，greasemonkey），firefox3.5+webkit的支持就已经足够罢。</p>
<p>如果不能无视主流平台，有很多技术能让你gracefully degrade（优雅的退化）或者选取不同的方法实现兼容的接口。</p>
<p>如果你等不及IE x在若干年后实现xx，希望提前享受福利，有些技术的设计原则就是让你能在没有native支持的情况下可以自己实现一模一样的功能或语法糖（syntactic sugar），比如ES5对象的继承和访问控制，从ES4/ActionScript3时期那些老土的关键词（class extands private static）改成了Object.create(p, attrs).defineProperty(o, n, attrs).defineProperties(o, attrs).freeze().getOwnPropertyNames().map(fn)，不会只是为了酷炫罢……</p>
<p>很多人都喜欢抱怨“我这辈子都没机会用HTML5”，但是只要把视线从自己脚下那巴掌大块地移开看看别处，会发现世界其实一直都在改变喔XD</p>
]]></content:encoded>
			<wfw:commentRss>http://www.limboy.com/2009/06/29/html5-css3-es5-support/feed/</wfw:commentRss>
		<slash:comments>16</slash:comments>
		</item>
		<item>
		<title>继续补充vim配置技巧——上次的vimrc还不够强力</title>
		<link>http://www.limboy.com/2009/06/07/vim-setting-more/</link>
		<comments>http://www.limboy.com/2009/06/07/vim-setting-more/#comments</comments>
		<pubDate>Sat, 06 Jun 2009 18:52:27 +0000</pubDate>
		<dc:creator>Dexter.Yy</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[OpenSource]]></category>
		<category><![CDATA[代码]]></category>
		<category><![CDATA[工具]]></category>

		<guid isPermaLink="false">http://www.limboy.com/2009/06/07/vim-setting-more/</guid>
		<description><![CDATA[首先要补充一些MacVim的配置，其实写上篇文章的时候我还在用已经过时的基于Carbon界面的vim for osx，更接近传统的unix版本，但是好久没更新，只支持vim6.0，soureforge上有一个7.2的版本，bug诸多，其中的乱码和字体抗锯齿的问题让我完全无法忍。而MacVim是基于Cocoa开发，支持到7.2，还含有很多讨好mac用户的设计，比如对标签的良好支持，华丽的界面（背景颜色支持透明度，字体抗锯齿更漂亮，几乎跟TextMate的效果没区别）……非常后悔以前没仔细试用这个版本！目前为止只发现行高linespace的设置会无法生效，不过这个bug在最新的快照版里已经修正了。
插播一个道歉：由于spam太多，我前段时间在wordpress黑名单里加了一个很苛刻的条件，把所有评论都挡到待审核列表里去了，好像还直接删了一部分……咳……
我在.vimrc里增加了一些专门针对MacVim的设置：
if has(&#34;gui_macvim&#34;)
&#160; &#34;取消默认的快捷键
&#160; let macvim_skip_cmd_opt_movement = 1 
&#160; let macvim_hig_shift_movement = 1
&#160; 
&#160; &#34;设置背景透明度
&#160; set transparency=2
&#160; &#34;隐藏工具条
&#160; set guioptions-=T &#34;egmrt
&#160; 
&#160; &#34;绑定自己需要的cmd快捷键
&#160; macm File.Save&#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; key=&#60;D-s&#62;
&#160; macm File.Save\ As\.\.\.&#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; key=&#60;D-S&#62;
&#160; macm [...]]]></description>
			<content:encoded><![CDATA[<p><a href='http://www.limboy.com/wp-content/uploads/2009/06/picture-4.png' title='picture-4.png' target="_blank"><img src='http://www.limboy.com/wp-content/uploads/2009/06/picture-4.png' alt='picture-4.png' style="width:200px;margin:0 10px 10px 0;float:left;" /></a>首先要补充一些<a href="http://code.google.com/p/macvim/" target="_blank">MacVim</a>的配置，其实写上篇文章的时候我还在用已经过时的<a href="http://macvim.org/OSX/index.php" target="_blank">基于Carbon界面的vim for osx</a>，更接近传统的unix版本，但是好久没更新，只支持vim6.0，soureforge上有一个<a href="http://sourceforge.net/project/showfiles.php?group_id=213254" target="_blank">7.2的版本</a>，bug诸多，其中的乱码和字体抗锯齿的问题让我完全无法忍。而MacVim是基于Cocoa开发，支持到7.2，还含有很多讨好mac用户的设计，比如对标签的良好支持，华丽的界面（背景颜色支持透明度，字体抗锯齿更漂亮，几乎跟TextMate的效果没区别）……非常后悔以前没仔细试用这个版本！目前为止只发现行高linespace的设置会无法生效，不过这个bug在<a href="http://code.google.com/p/macvim/wiki/Snapshot" target="_blank">最新的快照版</a>里已经修正了。</p>
<p>插播一个道歉：由于spam太多，我前段时间在wordpress黑名单里加了一个很苛刻的条件，把所有评论都挡到待审核列表里去了，好像还直接删了一部分……咳……<span id="more-236"></span></p>
<p>我在.vimrc里增加了一些专门针对MacVim的设置：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">if has(&quot;gui_macvim&quot;)</li>
<li>&nbsp; &quot;取消默认的快捷键</li>
<li>&nbsp; let macvim_skip_cmd_opt_movement = 1 </li>
<li>&nbsp; let macvim_hig_shift_movement = 1</li>
<li>&nbsp; </li>
<li>&nbsp; &quot;设置背景透明度</li>
<li>&nbsp; set transparency=2</li>
<li>&nbsp; &quot;隐藏工具条</li>
<li>&nbsp; set guioptions-=T &quot;egmrt</li>
<li>&nbsp; </li>
<li>&nbsp; &quot;绑定自己需要的cmd快捷键</li>
<li>&nbsp; macm File.Save&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; key=&lt;D-s&gt;</li>
<li>&nbsp; macm File.Save\ As\.\.\.&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; key=&lt;D-S&gt;</li>
<li>&nbsp; macm Edit.Undo&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; key=&lt;D-z&gt; action=undo:</li>
<li>&nbsp; macm Edit.Redo&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; key=&lt;D-Z&gt; action=redo:</li>
<li>&nbsp; macm Edit.Cut&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;key=&lt;D-x&gt; action=cut:</li>
<li>&nbsp; macm Edit.Copy&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; key=&lt;D-c&gt; action=copy:</li>
<li>&nbsp; macm Edit.Paste&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;key=&lt;D-v&gt; action=paste:</li>
<li>&nbsp; macm Edit.Select\ All&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;key=&lt;D-A&gt; action=selectAll:</li>
<li>endif</li></ol></div>
<p>之所以要取消MacVim默认的一些快捷键是因为它们都占用了cmd苹果键，而我习惯用这个键来替代ctrl在vim里的作用（在mbp的键盘上就算我想用ctrl也不方便……），不过其中有几个快捷键是非常非常有价值的，比如保存（省去了输入:w的麻烦），全选（否则要摁六下：ggVG），复制粘贴剪切（否则为了使用剪贴板，比如猛摁这种玩意：&#8221;+y，还不能在插入模式下使用 ），幸好它们的快捷键都不跟vim其他操作冲突，所以自己设置。为了完全删除MacVim默认的cmd快捷键，还需要打开app中自带的vimrc文件（可以这样编辑：:tabe $VIM/vimrc ），删除末尾那些macm开头的代码。<br />
<br/><br />
MacVim的安装包里包含一个mvim，是像gvim一样的脚本，用来在命令行中调用GUI版的vim，但是mvim默认会在新窗口打开文件，我相信多数人都喜欢在当前窗口的新标签页里打开罢，需要在命令后加&#8211;remote-tab参数，不过<a href="http://webexpose.org/2008/10/13/open-macvim-tabs-from-command-line" target="_blank">这篇文章</a>里给出了直接修改脚本的方法，把mvim底部从# Last step:  fire up vim开始的部分删掉，改成：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">tabs=true </li>
<li>&nbsp;</li>
<li># Last step:&nbsp; fire up vim. </li>
<li>if [ &quot;$gui&quot; ]; then </li>
<li>	if $tabs &amp;&amp; [[ `$binary --serverlist` = &quot;VIM&quot; ]]; then</li>
<li>	&nbsp; &nbsp;	exec &quot;$binary&quot; -g $opts --remote-tab-silent ${1:+&quot;$@&quot;} </li>
<li>	else </li>
<li>		exec &quot;$binary&quot; -g $opts ${1:+&quot;$@&quot;} </li>
<li>	fi </li>
<li>else </li>
<li>	exec &quot;$binary&quot; $opts ${1:+&quot;$@&quot;} </li>
<li>fi</li></ol></div>
<p>P.S. 上面给出的那个blog不能直接打开，也许是需要翻墙，不过我顺便介绍一个很方便的利用google网页快照的方法～ 用<a href="http://translate.google.cn/translate_t#zh-CN|en|" target="_blank">谷歌翻译</a>打开这个网址 XD<br />
<br/><br />
刚安装好的MacVim打开gb编码的文件仍然把中文显示成乱码（好无奈，GBK编码是土豆网的历史遗留问题，页面里的script标签也几乎都没加charset=&#8221;utf-8&#8243;，所以大部分js文件都只好用gb18030的编码，textmate正是因为不支持gb编码才被我降为二等公民的，其实我有正版cdkey……），我在.vimrc里加上了encoding似乎能解决这个问题：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">set encoding=utf-8</li>
<li>set fileencodings=utf-8,ucs-bom,gb18030,gbk,gb2312,cp936</li></ol></div>
<p>解释一下：对于编码，vim里有三个设置选项，encoding是设置vim以何种编码显示文件（缩写enc），fileencoding是当前文件实际的编码（缩写fenc）， 而fileencodings指示vim如何解码（缩写fencs），因此vim在打开一个文件时实际上会先根据fileencodings里的列表反复测试，直到成功解码，转换成encoding指定的编码，然后正常显示，转码的过程是用iconv实现的（所以windows上用vim还要配置iconv的dll路径和参数……麻烦），保存的时候会根据fileencoding来保存，跟是否显示为乱码没有关系。</p>
<p>所以如果想转换一个文件的编码，比如从utf-8转换到gb18030，可以在编辑器中直接输入两个命令：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">:set enc=gb18030</li>
<li>:set fenc=gb18030</li></ol></div>
<p>然后保存就ok了～其实如果不用继续编辑的话，第一行都可以省去，因为它的目的只是让编辑器用gb18030来显示当前文件，避免乱码，但是并不影响文件保存时的编码和正确性。</p>
<p>以前我都是依赖mac上的<a href="http://www.panic.com/coda/" target="_blank">Coda</a>来转换编码（确实最方便）……vim又成功了抢了它的饭碗……<br />
<br/><br />
MacVim还有一个问题是会显示一个很宅很不人性的标签栏名称，比如我编辑/usr/local/bin/mvim这个文件，标签栏上写的是“/u/l/b/mvim”，如果目录结构再深一点就看不到真正的文件名了，在.vimrc里加入下面这行可以让标签栏只显示文件名：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">set guitablabel=%t</li></ol></div>
<p><br/><br />
上次的.vimrc里还增加了两处很重要的设置，主要是受这位老爷写的<a href="http://easwy.com/blog/archives/advanced-vim-skills-catalog/" target="_blank">《vim使用进阶》</a>的启发，首先是让.vimrc每次编辑保存后自动生效，避免重启：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">autocmd! bufwritepost .vimrc source ~/.vimrc</li></ol></div>
<p>autocmd实际上是vim脚本的事件机制，表示在某个事件触发后自动执行的命令<br />
<br/><br />
接下来要实现的是保存和恢复编辑器的当前状态，类似Eclipse的Workspace，不过vim的session更强大，几乎可以还原一切状态……<a href="http://easwy.com/blog/archives/advanced-vim-skills-session-file-and-viminfo/" target="_blank">Easwy老爷介绍的命令</a>比较繁琐，缺乏“一键恢复”的快感……身为一个习惯使用“高级语言”的程序员，在这种时候就抑制不住继续封装和提高抽象层的欲望……所以自定义了以下两个命令：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">function! GetMySession(spath, ssname)</li>
<li>	if a:ssname == 0</li>
<li>		let a:sname = &quot;&quot;</li>
<li>	else</li>
<li>		let a:sname = &quot;-&quot;.a:ssname</li>
<li>	endif</li>
<li>	execute &quot;source $&quot;.a:spath.&quot;/session&quot;.a:sname.&quot;.vim&quot;</li>
<li>	execute &quot;rviminfo $&quot;.a:spath.&quot;/session&quot;.a:sname.&quot;.viminfo&quot;</li>
<li>	execute &quot;echo \&quot;Load Success\: $&quot;.a:spath.&quot;/session&quot;.a:sname.&quot;.vim\&quot;&quot;</li>
<li>endfunction</li>
<li>&nbsp;</li>
<li>function! SetMySession(spath, ssname)</li>
<li>	if a:ssname == 0</li>
<li>		let a:sname = &quot;&quot;</li>
<li>	else</li>
<li>		let a:sname = &quot;-&quot;.a:ssname</li>
<li>	endif</li>
<li>	execute &quot;cd $&quot;.a:spath</li>
<li>	execute &quot;mksession! $&quot;.a:spath.&quot;/session&quot;.a:sname.&quot;.vim&quot;</li>
<li>	execute &quot;wviminfo! $&quot;.a:spath.&quot;/session&quot;.a:sname.&quot;.viminfo&quot;</li>
<li>	execute &quot;echo \&quot;Save Success\: $&quot;.a:spath.&quot;/session&quot;.a:sname.&quot;.vim\&quot;&quot;</li>
<li>endfunction</li>
<li>&nbsp;</li>
<li>&quot; load session from certain path</li>
<li>command! -nargs=+ LOAD call GetMySession(&lt;f-args&gt;) </li>
<li>&nbsp;</li>
<li>&quot; load session from certain path</li>
<li>command! -nargs=+ SAVE call SetMySession(&lt;f-args&gt;)</li></ol></div>
<p>为了用最简单的方法选择路径，使用时需要先在终端的初始化脚本（比如~/.bashrc，在我的OSX系统里通常用~/.profile）里添加相应的环境变量，比如我常用的三个路径：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">export TUISVN=&quot;/Users/dexteryy/Sites/Tudou/ui/ui/&quot;</li>
<li>export TUIDEV=&quot;/Volumes/ui.tudou.com/&quot;</li>
<li>export MYWEB=&quot;/Users/dexteryy/Sites/www/&quot;</li></ol></div>
<p>当我在MYWEB的路径下做项目的时候，如果需要保存当前状态，只要输入:SAVE MYWEB 0就行了，这里的0是因为考虑到在同一个工作目录里可能需要使用到不同文件组合的工作区，提供的一个简单的版本号，这段命令执行后会在/Users/dexteryy/Sites/www/目录里生成两个文件： session.viminfo和session.vim，如果版本号是大于0的整数，比如2，文件名会是session2.viminfo和session2.viminfo</p>
<p>需要恢复的时候只要输入命令：:LOAD MYWEB 0  就行叻～</p>
<p>喔对了，为了能在VIM命令里使用bash中定义的变量，你需要在MacVim的preferences里把“Launch Vim processes in a login shell”勾选，熟悉Mac应用的同学应该都能想到这个设置会记录在/Library/Preferences/或~/Library/Preferences/里的某个配置文件里，MacVim对应的是~/Library/Preferences/org.vim.MacVim.plist，所以你也可以直接用这个命令在终端里修改：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">defaults write org.vim.MacVim MMLoginShell 1</li></ol></div>
<p>如果使用的是Gvim或windows版本的vim，也可以直接把路径变量写在.vimrc里，比如：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">let g:TUISVN=&quot;/Users/dexteryy/Sites/Tudou/ui/ui/&quot;</li></ol></div>
<p>然后修改上面的两个函数GetMySession和SetMySession，把a:spath前面的$都删掉…………因为VIM里的变量只能由大写字母开头……</p>
<p>完整的<a href="http://code.google.com/p/yy-vimscript/source/browse/trunk/vimrc">.vimrc</a>在这里…………呃好罢我发现google code真是备份和维护配置脚本的好地方XD<br />
<br/><br />
最后继续讨论一下插件～</p>
<p>首先是<a href="http://www.vim.org/scripts/script.php?script_id=273" target="_blank">Taglist</a>，这是一个能让vim具备类似Aptana的<a href="http://aptana.com/docs/index.php/Displaying_the_Outline_View" target="_blank">Outline View</a>的功能，还能像JAVA的IDE那样通过类名和方法名直接跳转到相应的源码，它借助了一个叫ctags的工具，可以解析源码生成标签文件（在同一个名录下，叫tags），详细的介绍请参考<a href="http://easwy.com/blog/archives/advanced-vim-skills-use-ctags-tag-file/" target="_blank">Easwy老爷的文章</a>，记得务必安装最新版的Exuberant Ctags……我是用MacPorts装的：sudo port install ctags</p>
<p>Exuberant Ctags号称支持34种语言，包括javascript，但是它对javascript的理解非常OUT……比如现在定义JS方法几乎主要依靠匿名函数了，ctags却无法识别这种形式……</p>
<p>已经<a href="http://weblogs.asp.net/george_v_reilly/archive/2009/03/24/exuberant-ctags-and-javascript.aspx" target="_blank">有人</a>在尝试自己添加匹配规则，我自己也写了一大坨：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">--langdef=js</li>
<li>--langmap=js:.js</li>
<li>--regex-js=/[ \t.]([A-Z][A-Z0-9._$]+)[ \t]*=[ \t]*[0-9&quot;'\[\{]/\1/n,constant/</li>
<li>--regex-js=/([A-Za-z0-9._$]+)[ \t]*=[ \t]*\{/\1/o,object/</li>
<li>--regex-js=/['&quot;]*([A-Za-z0-9_$]+)['&quot;]*[ \t]*:[ \t]*\{/\1/o,object/</li>
<li>--regex-js=/([A-Za-z0-9._$]+)\[[&quot;']([A-Za-z0-9_$]+)[&quot;']\][ \t]*=[ \t]*\{/\1\.\2/o,object/</li>
<li>--regex-js=/([A-Za-z0-9._$]+)\.prototype[ \t.=]/\1/c,class/</li>
<li>--regex-js=/([A-Za-z0-9._$]+)[ \t]*=[ \t]*\(function\(\)/\1/c,class/</li>
<li>--regex-js=/['&quot;]*([A-Za-z0-9_$]+)['&quot;]*:[ \t]*\(function\(\)/\1/c,class/</li>
<li>--regex-js=/var[ \t]*([A-Za-z$][A-Za-z0-9_$()]+)[ \t]*=[ \t]*function[ \t]*\(/\1/f,function/</li>
<li>--regex-js=/function[ \t]+([A-Za-z$][A-Za-z0-9_$]+)[ \t]*\(([^)])\)/\1/f,function/</li>
<li>--regex-js=/['&quot;]*([A-Za-z$][A-Za-z0-9_$]+)['&quot;]*:[ \t]*function[ \t]*\(/\1/m,method/</li>
<li>--regex-js=/([A-Za-z$][A-Za-z0-9_$]+)[ \t]*=[ \t]*function[ \t]*\(/\1/m,method/</li>
<li>--regex-js=/([A-Za-z0-9_$]+)\[[&quot;']([A-Za-z0-9_$]+)[&quot;']\][ \t]*=[ \t]*function[ \t]*\(/\2/m,method/</li>
<li>--regex-js=/([A-Za-z0-9._$]+)[ \t]*=[ \t]*\[/\1/a,array/</li>
<li>--regex-js=/['&quot;]*([A-Za-z$][A-Za-z0-9_$]+)['&quot;]*:[ \t]*\[/\1/a,array/</li>
<li>--regex-js=/([A-Za-z0-9._$]+)\[[&quot;']([A-Za-z0-9_$]+)[&quot;']\][ \t]*=[ \t]*\[/\1\.\2/a,array/</li></ol></div>
<p>匹配以下语法形式，其中粗体部分是标签名称：</p>
<ol>
<li>var <strong>MY_CONSTANT</strong> = 250; //constant</li>
<li><strong>ns.myobject</strong> = {}; //object</li>
<li><strong>myobject</strong>: {}, //object</li>
<li>ns["myobject"] = {}; //object, 生成的tag是&#8221;<strong>ns.myobject</strong>&#8220;</li>
<li><strong>ns.myclass</strong>.prototype.myfunc = function(){}; //class</li>
<li><strong>ns.myclass </strong>= (function(){return {};}); //class</li>
<li>ns["myclass"] = (function(){return {};}); //class, 生成的tag是&#8221;<strong>ns.myclass</strong>&#8220;</li>
<li>var <strong>myfunc</strong> = function(){}; //function, 必须有var, _开头的忽略</li>
<li>function <strong>myfunc</strong>(){}; //function</li>
<li><strong>myfunc</strong>: function(){} //method</li>
<li>ns.<strong>myfunc</strong> = function(){}; //method</li>
<li>ns["myfunc"] = function(){}; //method, 生成的tag是&#8221;ns.<strong>myfunc</strong>&#8220;</li>
<li><strong>ns.myarray</strong> = []; //array</li>
<li><strong>myarray</strong>: [], //array</li>
<li>ns["myarray"] = []; //array, 生成的tag是&#8221;<strong>ns.myarray</strong>&#8220;</li>
</ol>
<p>使用方法是建一个~/.ctags文件，把上面那段代码放进去就行。为了在taglist窗口里显示类别（比如class和method），还需要在.vimrc里设置一个变量：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">let g:tlist_javascript_settings = 'javascript;f:function;c:class;o:object;m:method;s:string;a:array;n:constant'</li></ol></div>
<p><br/><br />
另一个要强烈推荐的插件是<a href="http://www.vim.org/scripts/script.php?script_id=1218" target="_blank">NERD Commenter</a>，从名字能看出跟上次推荐的NERD Tree是同一个强者写的，功能是针对各种文件类型快速的添加和删除注释，除了单行，多行，还提供“sexily”的注释……比如js里添加文档内容时常用的那种（如果首行写成/**，在aptana里会认作script doc格式）</p>
<p>不过这个插件默认使用了大量,c开头的快捷键……而,在vim里一般都用作自定义的<leader>键（<leader>的默认值是\，很显然小拇指没食指方便……），我没有找到相关的设置选项……所以直接<a href="http://code.google.com/p/yy-vimscript/source/diff?spec=svn7&#038;r=7&#038;format=side&#038;path=/trunk/plugin/NERD_commenter.vim" target="_blank">修改</a>了插件脚本……<br />
<br/><br />
唔唔就先写到这里罢，虽然vim无论日常使用还是hack都很爽，但是写起来还是挺枯燥的，头有点晕555……</p>
]]></content:encoded>
			<wfw:commentRss>http://www.limboy.com/2009/06/07/vim-setting-more/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>面向前端开发者和TextMate粉丝的vim配置</title>
		<link>http://www.limboy.com/2009/05/30/vim-setting/</link>
		<comments>http://www.limboy.com/2009/05/30/vim-setting/#comments</comments>
		<pubDate>Sat, 30 May 2009 14:21:23 +0000</pubDate>
		<dc:creator>Dexter.Yy</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[OpenSource]]></category>
		<category><![CDATA[代码]]></category>
		<category><![CDATA[工具]]></category>

		<guid isPermaLink="false">http://www.limboy.com/2009/05/30/vim-setting/</guid>
		<description><![CDATA[vim是编辑器中的神器，但是因为学习曲线比较陡，界面也仿佛从石器时代穿越，广大fashion的前端工作者们难免对其有距离感。其实vim最大的萌点有两个，其一是百科全书般的文本编辑功能，其二是可以随意定制，满足任何与编辑器相关的需求和偏好，比如下面这张便是我在macbook pro上运行vim的截图，不仅语法高亮可以冒充TextMate，功能也几乎一致。

首先是做一个初始化配置脚本，在我的OSX10.5里是是~/.vimrc文件，这里只列出一些需要补充进去的设置：
&#34;设置语法高亮的配色，在GUI界面里使用我自定义的yytextmate.vim
if has(&#34;gui_running&#34;)
	colorscheme yytextmate
else
	colorscheme slate
endif
&#34;查找编码的规则（vim7默认都用utf-8，打开包含gbk字符的文件会出现乱码）
set fileencodings=utf-8,ucs-bom,gb18030,gbk,gb2312,cp936
&#34;GUI界面里的字体，默认有抗锯齿
set guifont=Monaco:h12:cANSI
&#34;行间距，如果默认值太小，代码会非常纠结
set linespace=4&#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160;
&#34;用&#60;&#62;调整缩进时的长度
set shiftwidth=4 
&#34;制表符的长度，统一为4个空格的宽度
set tabstop=4
&#34;初始窗口的宽度
set columns=195
&#34;初始窗口的高度
set lines=45
&#34;初始窗口的位置
winpos 52 42
&#160;
&#34;显示行号
set number
&#34;行号栏的宽度
set numberwidth=4
&#160;&#34;禁止自动换行
set nowrap
&#34;在输入命令时列出匹配项目，也就是截图底部的效果
set wildmenu
&#34;显示光标位置
set ruler
&#34;分割窗口时保持相等的宽/高
set [...]]]></description>
			<content:encoded><![CDATA[<p><a href='http://www.limboy.com/2009/05/30/vim-setting/vim-editor-icon1png/' rel='attachment wp-att-235' title='vim-editor-icon1.png'><img src='http://www.limboy.com/wp-content/uploads/2009/05/vim-editor-icon1.png' alt='vim-editor-icon1.png' style="float:left;border:0;margin:0 0 0px 10px;" /></a><a href='http://www.limboy.com/wp-content/uploads/2009/05/textmate.png' title='textmate.png'><img src='http://www.limboy.com/wp-content/uploads/2009/05/textmate.png' alt='textmate.png' style="float:left;border:0;margin:0 10px 0px 0px;" /></a>vim是编辑器中的神器，但是因为学习曲线比较陡，界面也仿佛从石器时代穿越，广大fashion的前端工作者们难免对其有距离感。其实vim最大的萌点有两个，其一是百科全书般的文本编辑功能，其二是可以随意定制，满足任何与编辑器相关的需求和偏好，比如下面这张便是我在macbook pro上运行vim的截图，不仅语法高亮可以冒充<a href="http://macromates.com/" target="_blank">TextMate</a>，功能也几乎一致。<span id="more-230"></span></p>
<p><a href='http://www.limboy.com/wp-content/uploads/2009/05/picture-4.png' title='picture-4.png'><img src='http://www.limboy.com/wp-content/uploads/2009/05/picture-4.png' alt='picture-4.png' style="width:400px;" /></a></p>
<p>首先是做一个初始化配置脚本，在我的OSX10.5里是是~/.vimrc文件，这里只列出一些需要补充进去的设置：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">&quot;设置语法高亮的配色，在GUI界面里使用我自定义的yytextmate.vim</li>
<li>if has(&quot;gui_running&quot;)</li>
<li>	colorscheme yytextmate</li>
<li>else</li>
<li>	colorscheme slate</li>
<li>endif</li>
<li>&quot;查找编码的规则（vim7默认都用utf-8，打开包含gbk字符的文件会出现乱码）</li>
<li>set fileencodings=utf-8,ucs-bom,gb18030,gbk,gb2312,cp936</li>
<li>&quot;GUI界面里的字体，默认有抗锯齿</li>
<li>set guifont=Monaco:h12:cANSI</li>
<li>&quot;行间距，如果默认值太小，代码会非常纠结</li>
<li>set linespace=4&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</li>
<li>&quot;用&lt;&gt;调整缩进时的长度</li>
<li>set shiftwidth=4 </li>
<li>&quot;制表符的长度，统一为4个空格的宽度</li>
<li>set tabstop=4</li>
<li>&quot;初始窗口的宽度</li>
<li>set columns=195</li>
<li>&quot;初始窗口的高度</li>
<li>set lines=45</li>
<li>&quot;初始窗口的位置</li>
<li>winpos 52 42</li>
<li>&nbsp;</li>
<li>&quot;显示行号</li>
<li>set number</li>
<li>&quot;行号栏的宽度</li>
<li>set numberwidth=4</li>
<li>&nbsp;&quot;禁止自动换行</li>
<li>set nowrap</li>
<li>&quot;在输入命令时列出匹配项目，也就是截图底部的效果</li>
<li>set wildmenu</li>
<li>&quot;显示光标位置</li>
<li>set ruler</li>
<li>&quot;分割窗口时保持相等的宽/高</li>
<li>set equalalways</li>
<li>&nbsp;</li>
<li>&nbsp;&quot;匹配括号的规则，增加针对html的&lt;&gt;</li>
<li>set matchpairs=(:),{:},[:],&lt;:&gt;</li>
<li>&quot;让退格，空格，上下箭头遇到行首行尾时自动移到下一行（包括insert模式）</li>
<li>set whichwrap=b,s,&lt;,&gt;,[,]</li>
<li>&quot;取消自动备份</li>
<li>set nobackup</li>
<li>&quot;保存关闭文件之前保留一个备份</li>
<li>set writebackup</li>
<li>&nbsp;</li>
<li>&quot;js语法高亮脚本的设置</li>
<li>let g:javascript_enable_domhtmlcss=1</li>
<li>&nbsp;</li>
<li>&quot;设置自定义的&lt;leader&gt;快捷键</li>
<li>let mapleader=&quot;,&quot;</li>
<li>let g:mapleader=&quot;,&quot;</li>
<li>&nbsp;</li>
<li>&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;</li>
<li>&quot; bufExplorer插件的设置</li>
<li>&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;</li>
<li>let g:bufExplorerSortBy='mru'</li>
<li>let g:bufExplorerSplitRight=0&nbsp; &nbsp; &nbsp; </li>
<li>let g:bufExplorerSplitVertical=1&nbsp; &nbsp; .</li>
<li>let g:bufExplorerSplitVertSize = 30&nbsp; </li>
<li>let g:bufExplorerUseCurrentWindow=1&nbsp; </li>
<li>autocmd BufWinEnter \[Buf\ List\] setl nonumber</li>
<li>&nbsp;</li>
<li>&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;</li>
<li>&quot; winManager插件的设置</li>
<li>&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;</li>
<li>let g:winManagerWindowLayout = &quot;BufExplorer,FileExplorer|TagList&quot;</li>
<li>let g:winManagerWidth = 30</li>
<li>let g:defaultExplorer = 0</li>
<li>nmap &lt;silent&gt; &lt;leader&gt;wm :WMToggle&lt;cr&gt; </li>
<li>&nbsp;</li>
<li>&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;</li>
<li>&quot; netrw插件的快捷键</li>
<li>&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;</li>
<li>let g:netrw_winsize = 30</li>
<li>nmap &lt;silent&gt; &lt;leader&gt;fe :Sexplore!&lt;cr&gt;</li>
<li>&nbsp;</li>
<li>&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;</li>
<li>&quot; NERDTree插件的快捷键</li>
<li>&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;&quot;</li>
<li>nmap &lt;silent&gt; &lt;leader&gt;nt :NERDTree&lt;cr&gt;</li>
<li>&nbsp;</li>
<li>&nbsp;</li>
<li>&quot;把常用的ctrl快捷键映射到苹果键上（只保留cmd+c/cmd+v/cmd+z原有的功能）</li>
<li>map &lt;D-y&gt; &lt;C-y&gt;</li>
<li>map &lt;D-e&gt; &lt;C-e&gt;</li>
<li>map &lt;D-f&gt; &lt;C-f&gt;</li>
<li>map &lt;D-b&gt; &lt;C-b&gt;</li>
<li>map &lt;D-u&gt; &lt;C-u&gt;</li>
<li>map &lt;D-d&gt; &lt;C-d&gt;</li>
<li>map &lt;D-w&gt; &lt;C-w&gt;</li>
<li>map &lt;D-r&gt; &lt;C-r&gt;</li>
<li>map &lt;D-o&gt; &lt;C-o&gt;</li>
<li>map &lt;D-i&gt; &lt;C-i&gt;</li>
<li>map &lt;D-g&gt; &lt;C-g&gt;</li>
<li>map &lt;D-p&gt; &lt;C-p&gt;</li>
<li>map &lt;D-n&gt; &lt;C-n&gt;</li>
<li>map &lt;D-a&gt; &lt;C-a&gt;</li>
<li>cmap &lt;D-d&gt; &lt;C-d&gt;</li></ol></div>
<p>2009.6.7更新：最新的<a href="http://code.google.com/p/yy-vimscript/source/browse/trunk/vimrc" target="_blank">vimrc</a>和其他脚本已经上传到google code的项目仓库里了<br />
<br/><br />
=================步骤二的分割线===================<br />
<br/><br />
然后在个人配置目录里添加语法高亮脚本（~/.vim/syntax/），其中html和css可以直接把vim7自带的脚本复制出来（$VIMRUNTIME/syntax/），js的脚本则推荐用这个：</p>
<p><a href="http://www.vim.org/scripts/script.php?script_id=1491" target="_blank">JavaScript syntax : Better JavaScrirpt syntax support<br />
</a></p>
<p>包含更多的关键字以及自动折叠代码的功能，也能在html文件内支持js语法高亮，需要注意的是如果要支持dom方法的关键字，需要在.vimrc里设置一个全局变量javascript_enable_domhtmlcss</p>
<p>我还用了这里的<a href="htmhttp://www.fleiner.com/vim/download.html" target="_blank">html.vim</a>。<br />
<br/><br />
=================步骤三的分割线===================<br />
<br/><br />
接下来就可以对照着syntax脚本，给每个语法组设置颜色，配色脚本需要放到~/.vim/colors/里，然后在.vimrc里用colorscheme命令选定。colors脚本只需要一个，因为syntax脚本末尾都会把自定义的语法组链接到标准语法组，比如：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">HiLink javaScriptDocComment&nbsp; Comment</li></ol></div>
<p>所以只需要定义一套针对标准语法组的配色方案，再通过修改syntax脚本里来调整相应语言的配色。我尝试过针对不同文件类型使用不同的配色方案，发现相当麻烦，需要在切换/打开/关闭缓冲区和窗口的时候都用colorscheme重置配色：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">autocmd BufNewFile,BufRead,BufEnter,WinEnter,FileType *.html,*.htm colorscheme delek</li></ol></div>
<p>而且colorscheme会影响整个窗口（一个vim进程实例），如果在窗口内同时分割显示了几个文件，即使文件类型不同，也会同时改变颜色……</p>
<p>我平时最喜欢TextMate的Blackboard主题（大概是因为里面有橙色罢XD），在Aptana上也仿制过（配置文件：<a href="http://www.limboy.com/conf/eclipse/yytextmate.col" target="_blank">yytextmate.col</a>），这次是直接在vim的slate主题基础上修改出来的，比vim.org上面那个<a href="http://www.vim.org/scripts/script.php?script_id=2280" target="_blank">blackboard.vim</a>要更完善～</p>
<p>我的colors脚本：<a href="http://code.google.com/p/yy-vimscript/source/browse/trunk/colors/yytextmate.vim" target="_blank">yytextmate.vim</a><br />
我调整过的syntax脚本：<a href="http://code.google.com/p/yy-vimscript/source/browse/trunk/syntax/javascript.vim" target="_blank">javascript.vim</a>, <a href="http://code.google.com/p/yy-vimscript/source/browse/trunk/syntax/html.vim" target="_blank">html.vim</a><br />
<br/><br />
=================步骤四的分割线===================<br />
<br/><br />
按照由外向内的顺序，现在该折腾功能了，首先是缩进插件，vim也自带有智能缩进功能，需要开启autoindent和smartindent参数，但是在编辑js代码的时候效果很不好，对于python这种靠缩进活命的语言就更不能忍了，因此至少需要装以下三个插件：</p>
<p><a href="http://www.vim.org/scripts/script.php?script_id=1839"  target="_blank">IndentAnything : Write indentations or enhance existing indentations without writing code</a><br />
<a href="http://www.vim.org/scripts/script.php?script_id=1840"  target="_blank">Javascript Indentation : Indentation for Javascript </a><br />
<a href="http://www.vim.org/scripts/script.php?script_id=974"  target="_blank">indent/python.vim : An alternative indentation script for python<br />
</a></p>
<p>第一个放到~/.vim/plugin/里，后两个放在~/.vim/indent/里<br />
<br/><br />
=================步骤五的分割线===================<br />
<br/><br />
<a href='http://www.limboy.com/wp-content/uploads/2009/05/textmate.png' title='textmate.png'><img src='http://www.limboy.com/wp-content/uploads/2009/05/textmate.png' alt='textmate.png' style="float:left;border:0;margin:0 10px 10px 0;" /></a>接下来终于要来实现TextMate最重要的功能了，TextMate之所以被称作地上最贵麦上最强的编辑器，就是因为支持大量可以通过tab或其他快捷键发动的强力Bundles，这些Bundles可以分为两种类型，一种是针对编辑器的内容执行指令（称作command），比如直接执行shell脚本，压缩js代码，对html转义，格式化JSON，编译swf等等，而指令界面是vim的核心，不但可以直接执行shell命令，也可以通过设置键位映射和宏，把复杂的操作绑定成简单的快捷键，因此这类功能原本就是vim的强项。</p>
<p>另一种类型的Bundles主要用来帮助程序员快速开发，通过简短的缩写＋tab键直接生成所需的代码模板（称作snippet），然后依然用tab在模板中需要改动的位置之间跳转，整个过程不需要鼠标定位，非常高效，是一种比大型IDE里常见的&#8221;code hinting&#8221;更实用的智能补全功能。</p>
<p><a href="http://www.vim.org/scripts/script.php?script_id=2540"  target="_blank">snipMate : TextMate-style snippets for Vim</a></p>
<p>上面这个非常“新”的插件让vim也具备了同样的功能，而且几乎是跟TextMate完全兼容的移植，比如这是从TextMate里取出的snippet源码：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Gray;">$</span><span style="color: Olive;">{</span><span style="color: Maroon;">1</span><span style="color: Gray;">:</span><span style="color: Blue;">class_name</span><span style="color: Olive;">}</span><span style="color: Gray;">.</span><span style="color: Blue;">prototype</span><span style="color: Gray;">.$</span><span style="color: Olive;">{</span><span style="color: Maroon;">2</span><span style="color: Gray;">:</span><span style="color: Blue;">method_name</span><span style="color: Olive;">}</span><span style="color: Gray;"> = </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Gray;">$</span><span style="color: Olive;">{</span><span style="color: Maroon;">3</span><span style="color: Gray;">:</span><span style="color: Blue;">first_argument</span><span style="color: Olive;">})</span><span style="color: Gray;"> </span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; $</span><span style="color: Olive;">{</span><span style="color: Maroon;">0</span><span style="color: Gray;">:</span><span style="color: #ffa500;">// body...}</span></li>
<li><span style="color: Olive;">}</span><span style="color: Gray;">;</span></li></ol></div>
<p>${}标签是代码插入后可以通过tab跳转的“可编辑”位置，其中的序号表示跳转顺序，冒号后的字符是默认内容。这段代码只要在前面加上snippet proto就可以直接放进~/.vim/snippets/javascript.snippets里，通过proto<tab>触发</p>
<p>把常见的程序结构抽象成snippet可以节省很多重复输入，比如这是我定义的一个module模式：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">snippet</span><span style="color: Gray;"> </span><span style="color: Blue;">module</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: #ffa500;">/**</span></li>
<li><span style="color: #ffa500;">&nbsp; &nbsp;&nbsp; * ${5:Describe what this module does}</span></li>
<li><span style="color: #ffa500;">&nbsp; &nbsp;&nbsp; * @param {object} ${6:paramName}</span></li>
<li><span style="color: #ffa500;">&nbsp; &nbsp;&nbsp; */</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;"> $</span><span style="color: Olive;">{</span><span style="color: Maroon;">1</span><span style="color: Gray;">:</span><span style="color: Blue;">classname</span><span style="color: Olive;">}</span><span style="color: Gray;"> = </span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;"> $</span><span style="color: Maroon;">1</span><span style="color: Blue;">Object</span><span style="color: Gray;"> = </span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $</span><span style="color: Olive;">{</span><span style="color: Maroon;">2</span><span style="color: Gray;">:</span><span style="color: Blue;">privateMethod1</span><span style="color: Olive;">}</span><span style="color: Gray;">: </span><span style="color: Green;">function</span><span style="color: Olive;">(){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $</span><span style="color: Olive;">{</span><span style="color: Maroon;">3</span><span style="color: Gray;">:</span><span style="color: Blue;">privateMethod2</span><span style="color: Olive;">}</span><span style="color: Gray;">: </span><span style="color: Green;">function</span><span style="color: Olive;">(){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">}</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">opt</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">publicObj</span><span style="color: Gray;"> = </span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">options</span><span style="color: Gray;">: </span><span style="color: Olive;">{}</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $</span><span style="color: Maroon;">2</span><span style="color: Gray;">: $</span><span style="color: Maroon;">1</span><span style="color: Blue;">Object</span><span style="color: Gray;">.$</span><span style="color: Maroon;">2</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $</span><span style="color: Maroon;">3</span><span style="color: Gray;">: $</span><span style="color: Maroon;">1</span><span style="color: Blue;">Object</span><span style="color: Gray;">.$</span><span style="color: Maroon;">3</span><span style="color: Gray;">$</span><span style="color: Olive;">{</span><span style="color: Maroon;">4</span><span style="color: Gray;">:,</span><span style="color: Olive;">}</span><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; $.</span><span style="color: Blue;">extend</span><span style="color: Olive;">(</span><span style="color: Blue;">publicObj</span><span style="color: Gray;">.</span><span style="color: Blue;">options</span><span style="color: Gray;">, </span><span style="color: Blue;">opt</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">publicObj</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">})()</span><span style="color: Gray;">;</span></li></ol></div>
<p>修改过程中会看到$1,$2,$3自动更新成你键入的名字。</p>
<p>我修改过的完整javascript.snippets：<a href="http://code.google.com/p/yy-vimscript/source/browse/trunk/snippets/javascript.snippets" target="_blank">http://code.google.com/p/yy-vimscript/source/browse/trunk/snippets/javascript.snippets</a></p>
<p>实际上还有一个比较老牌的插件也致力于实现同样的snippet功能：</p>
<p><a href="http://www.vim.org/scripts/script.php?script_id=1318" target="_blank">snippetsEmu : An attempt to emulate TextMate&#8217;s snippet expansion</a></p>
<p>但是它支持的模板语法比TextMate差很多，跟上面相同的prototype模板要通过这种形式定义：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">let st = g:snip_start_tag</li>
<li>let et = g:snip_end_tag</li>
<li>let cd = g:snip_elem_delim</li>
<li>&nbsp;</li>
<li>exec &quot;Snippet proto &quot;.st.&quot;className&quot;.et.&quot;.prototype.&quot;.st.&quot;methodName&quot;.et.&quot; = function(&quot;.st.et.&quot;)&lt;CR&gt;{&lt;CR&gt;&quot;.st.et.&quot;&lt;CR&gt;};&lt;CR&gt;&quot;.st.et</li></ol></div>
<p>缩进容易出错，不支持用序号设定跳转顺序，安装过程也比snipMate繁复，所以被我毫不留恋的淘汰了……</p>
<p>为了实现更广泛的智能补全，还需要一个必装插件：</p>
<p><a href="http://www.vim.org/scripts/script.php?script_id=1643" target="_blank">SuperTab continued. : Do all your insert-mode completion with Tab. </a></p>
<p>SuperTab让任意字符都可以通过tab补全，比较取巧的是，它会在缓冲区的上下文中寻找匹配的词来补全，因此不需要附带很庞大的API数据。<br />
<br/><br />
=================步骤六的分割线===================<br />
<br/><br />
下一步需要增强的是文件/项目管理，vim虽然自带一个FileExplorer（直接编辑一个目录时会调用它，比如:e .），还有上面提到过的wildmenu的强力辅助，但是与常见的GUI编辑器和IDE相比，仍然不太直观，因此以下插件值得一装：</p>
<p><a href="http://www.vim.org/scripts/script.php?script_id=1658" target="_blank">The NERD tree : A tree explorer plugin for navigating the filesystem</a><br />
我最喜欢的文件导航工具，设置了快捷键,nt直接在侧面打开</p>
<p><a href="http://vim.sourceforge.net/scripts/script.php?script_id=42" target="_blank">bufexplorer : Buffer Explorer / Browser </a><br />
缓冲区导航</p>
<p><a href="http://www.vim.org/scripts/script.php?script_id=95" target="_blank">winmanager : A windows style IDE for Vim 6.0</a><br />
把bufexploer和FileExplorer集成在左侧，类似IDE的效果，这个功能不足以让我放弃NERDTree……而且这个插件似乎很久没更新了，连支持Vim7的版本都没有，但是很多人喜欢，所以也推荐一下…… </p>
<p><a href="http://www.vim.org/scripts/script.php?script_id=2607" target="_blank">TaskList.vim : Eclipse like task list</a><br />
实现Eclipse的任务列表</p>
<p><a href="http://www.vim.org/scripts/script.php?script_id=69" target="_blank">project.tar.gz : Organize/Navigate projects of files</a><br />
项目导航工具，不过没有Eclipse好用，需要写配置脚本，跟TextMate那种拖来拖去的drawer就更不能比了……<br />
<br/><br />
=================步骤七的分割线===================<br />
<br/><br />
最后推荐的插件都是开发工具：</p>
<p><a href="http://www.vim.org/scripts/script.php?script_id=90" target="_blank">vcscommand.vim : CVS/SVN/SVK/git integration plugin</a><br />
SVN/git管理工具，这个是必备罢。没有GUI菜单，不过快捷键也很方便，而且VimDiff是很棒的比较工具</p>
<p><a href="http://www.vim.org/scripts/script.php?script_id=2578" target="_blank">javaScriptLint.vim : Displays JavaScript Lint warnings in the quickfix error window</a><br />
看仔细啦～这个不是道格拉斯老爷子的JSLint，那个东西虽然强大（以前没觉得，最近在《代码之美》里看到道格拉斯老爷子描述了“递归下降分析”＋“运算符优先级技术”的动态语言解释器，才知道原来JSLint和JSON parser只是老爷子晒技术的承载体……），但是由于把规范约束在一个JS的安全子集上，适用面不广，设置起来也麻烦，在实际开发工作中未必实用。而<a href="http://javascriptlint.com/" target="_blank">这个Lint</a>就很中规中矩，当然也没自己折腾解释器啦，直接用了Mozilla的js引擎，安装也很方便，提供一个conf文件可以设置警告条件。这个vim插件装上后，保存js文件时都会自动校验代码并显示一个提示信息窗口。</p>
<p><a href="http://www.vim.org/scripts/script.php?script_id=39" target="_blank">matchit : extended % matching for HTML, LaTeX, and many other languages</a><br />
vim里的%命令可以在嵌套字符之间跳转（比如括号和引号，我在上面的.vimrc文件里增加了html的<>），这个插件将它的功能扩展到嵌套标签和语句</p>
<p>To be <a href="http://www.limboy.com/2009/06/07/vim-setting-more/" target="_blank">continue</a>&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.limboy.com/2009/05/30/vim-setting/feed/</wfw:commentRss>
		<slash:comments>25</slash:comments>
		</item>
		<item>
		<title>土豆招聘Javascript工程师的JD，终于谷出来一个</title>
		<link>http://www.limboy.com/2009/05/16/yet-another-javascript-jd/</link>
		<comments>http://www.limboy.com/2009/05/16/yet-another-javascript-jd/#comments</comments>
		<pubDate>Sat, 16 May 2009 08:34:02 +0000</pubDate>
		<dc:creator>Dexter.Yy</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[代码]]></category>
		<category><![CDATA[土豆网]]></category>

		<guid isPermaLink="false">http://www.limboy.com/2009/05/16/yet-another-javascript-jd/</guid>
		<description><![CDATA[原本是小麦的文案，被我改的啰嗦了，虽然最近在地铁上读了The Elements of Style，但是文字要写的简洁真的需要足够冷酷，我热血而且贪婪，不忍心漏掉一个信息点，所以简洁与我无缘……这篇JD发到其他地方的时候可能会删减很多，我先自己留一份……另外虽然这份JD仅仅提出了对雇员的要求，没有介绍雇主，但如果你仍然有兴趣，可以直接给我发email。
职位：Javascript开发工程师
简单的说，我们需要的是能“正确”使用Javascript的开发者。不同情况下，“正确”的标准也不尽然相同，作为土豆的javascript工程师，我们希望你大致符合如下的描述：

熟悉JS的语法特性和运行机制，比如词法作用域，闭包，原型链，无类型的OO，并乐于在此基础上钻研和探索用JS开发富客户端和复杂web应用的最佳实践和设计模式（这句话用英文写还蛮好，中文怎么拆哑啊啊啊啊～）
jQuery、YUI、MooTools等JS库，对你来说不仅只是开发工具，更是你学习代码风格、接口设计与程序架构的良师益友，你愿意了解他们，不盲目遵从，也不随意使唤。
重视团队协作，愿意探寻和改进目前还不成熟的前端开发流程，了解各种常用工具，如Firebug，YSlow，JSLint，YUI compressor……
在前端领域，你发布过一些有趣的个人项目，或是参与过开源项目，或是致力于构建自己的库和开发框架，或是作为团队核心成员开发过产品级的web应用。
一些基本前端技能如CSS或PS切图就毋需赘述了。

此外，我们乐见一些更优秀的特质：

持续关注业界的新话题和新技术。你喜欢泡在javaeye，reddit之类技术社区灌水和答疑解惑，或者总是最早读到John Resig，Douglas Crackford，Dion Almae，PPK，Dean Edwards等大牛们的新作品和演讲ppt，或者长年维护自己的博客，分享自己的经验和新实践。
你具备其他语言的开发经验，比如java和php，比如Actionscript3/Flex。这给你带来了更深入的程序设计经验和更高更全面的视角。
对于浏览器中的各种可用资源、特性和差异，你都玩弄于鼓掌之间，你有大量优化和重构方面的经验，致力于编写安全，稳定，简洁而强壮，易于扩展的客户端代码。

以上不是必需的，但如果你完全符合，我们可以考虑将土豆网总部迁至你家附近（哈哈）。
最后，如果你目前还不符合以上的描述，但很渴望做到这些，我们也很愿意为你提供面谈的机会。
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;最后吐槽的分割线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-
我觉得小麦写的最后两句是经典哑，一个字未改～
PS：题图其实是蜘蛛侠里的犀牛人……
]]></description>
			<content:encoded><![CDATA[<p><a href='http://www.limboy.com/wp-content/uploads/2009/05/rhino-a-5001.jpg' title='rhino-a-5001.jpg'><img src='http://www.limboy.com/wp-content/uploads/2009/05/rhino-a-5001.jpg' alt='rhino-a-5001.jpg' style="width:250px;float:left;margin:0 10px 10px 0;" /></a>原本是<a href="http://www.mikkolee.com/" target="_blank">小麦</a>的文案，被我改的啰嗦了，虽然最近在地铁上读了<a href="http://www.douban.com/subject/1433835/">The Elements of Style</a>，但是文字要写的简洁真的需要足够冷酷，我热血而且贪婪，不忍心漏掉一个信息点，所以简洁与我无缘……这篇JD发到其他地方的时候可能会删减很多，我先自己留一份……另外虽然这份JD仅仅提出了对雇员的要求，没有介绍雇主，但如果你仍然有兴趣，可以直接给我发email。</p>
<p><strong>职位：Javascript开发工程师</strong></p>
<p>简单的说，我们需要的是能“正确”使用Javascript的开发者。不同情况下，“正确”的标准也不尽然相同，作为土豆的javascript工程师，我们希望你大致符合如下的描述：<span id="more-228"></span></p>
<ul>
<li>熟悉JS的语法特性和运行机制，比如词法作用域，闭包，原型链，无类型的OO，并乐于在此基础上钻研和探索用JS开发富客户端和复杂web应用的最佳实践和设计模式（<em>这句话用英文写还蛮好，中文怎么拆哑啊啊啊啊～</em>）</li>
<li>jQuery、YUI、MooTools等JS库，对你来说不仅只是开发工具，更是你学习代码风格、接口设计与程序架构的良师益友，你愿意了解他们，不盲目遵从，也不随意使唤。</li>
<li>重视团队协作，愿意探寻和改进目前还不成熟的前端开发流程，了解各种常用工具，如Firebug，YSlow，JSLint，YUI compressor……</li>
<li>在前端领域，你发布过一些有趣的个人项目，或是参与过开源项目，或是致力于构建自己的库和开发框架，或是作为团队核心成员开发过产品级的web应用。</li>
<li>一些基本前端技能如CSS或PS切图就毋需赘述了。</li>
</ul>
<p>此外，我们乐见一些更优秀的特质：</p>
<ul>
<li>持续关注业界的新话题和新技术。你喜欢泡在javaeye，reddit之类技术社区灌水和答疑解惑，或者总是最早读到John Resig，Douglas Crackford，Dion Almae，PPK，Dean Edwards等大牛们的新作品和演讲ppt，或者长年维护自己的博客，分享自己的经验和新实践。</li>
<li>你具备其他语言的开发经验，比如java和php，比如Actionscript3/Flex。这给你带来了更深入的程序设计经验和更高更全面的视角。</li>
<li>对于浏览器中的各种可用资源、特性和差异，你都玩弄于鼓掌之间，你有大量优化和重构方面的经验，致力于编写安全，稳定，简洁而强壮，易于扩展的客户端代码。</li>
</ul>
<p>以上不是必需的，但如果你完全符合，我们可以考虑将土豆网总部迁至你家附近（哈哈）。</p>
<p>最后，如果你目前还不符合以上的描述，但很渴望做到这些，我们也很愿意为你提供面谈的机会。</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;最后吐槽的分割线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>我觉得小麦写的最后两句是经典哑，一个字未改～</p>
<p>PS：题图其实是蜘蛛侠里的犀牛人……</p>
]]></content:encoded>
			<wfw:commentRss>http://www.limboy.com/2009/05/16/yet-another-javascript-jd/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>写javascript是否要“预留退路”</title>
		<link>http://www.limboy.com/2009/01/20/is_javascript_need_degradation/</link>
		<comments>http://www.limboy.com/2009/01/20/is_javascript_need_degradation/#comments</comments>
		<pubDate>Tue, 20 Jan 2009 08:31:36 +0000</pubDate>
		<dc:creator>Dexter.Yy</dc:creator>
				<category><![CDATA[Blogger]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[web服务/应用]]></category>
		<category><![CDATA[用户体验]]></category>
		<category><![CDATA[纯水]]></category>

		<guid isPermaLink="false">http://www.limboy.com/2009/01/20/is_javascript_need_degradation/</guid>
		<description><![CDATA[早上收到一封邮件，问的正好是我一直如哽在喉的事情：
对于web开发中的预留退路问题，我一直犹豫不决。在安全方面，自然是不能完全相信JavaScript，这点是确定的。但在用户体验方面，是否真的需要处处&#8221;预留退路&#8221;，照顾那些不支持JS或者对JS支持不好的用户吗？而UED工程师们又一直在说，不&#8221;预留退路&#8221;会惹恼数量不少的用户，但却从没有人提起具体会是多少用户、多少比例。不知道YY大神手里有这方面的数据吗？记得YY您在建立Limbo混沌海的时候，就选择了&#8221;不预留退路&#8221;的方式，不知当初又是出于什么原因这样考虑的呢？非常想听听您对&#8221;预留退路&#8221;问题的看法，期待您的回信。

这种设计观念，或者说原则，不管它叫什么名字，比如“预留退路”/“平稳退化”（Graceful Degradation），“渐进增强”（Progressive Enhancement），“不唐突的javascript”（Unobtrusive JavaScript）……从UE的角度来说是非常重要的，它的重要性不仅仅来自“有多少比例的用户不开启javascript支持”，而是因为如今访问web的方式正在变的越来越丰富多样，平板电脑（Tablet PC），上网本（netbook），掌上电脑（UMPC/MID），手机，iphone/ipod touch，这些平台有完全不同的性能，屏幕尺寸，浏览器，和操作方式，它们对javascript的支持也可能不一致（比如我以前抱怨过iphone的差别）。很多“严肃”的网站还需要考虑到“可访问性”（Accessibility），要保证能支持屏幕阅读器之类的设备，让那些有视觉缺陷的用户也可以无障碍的使用。此外还有语义网方面的要求，随着web2.0带来的海量信息，互联网也在向一台超级计算机的方向发展，需要靠网络本身去处理网络上的信息，而不是靠人的肉眼去一张网页一张网页的识别，现在的网页不仅仅是供人阅读，同样也需要面向机器，所以不能因为javascript的使用而影响到内容，让机器无法抓取和识别。
不过，以上这些观念有两方面的局限性：

第一，它们仅仅适用于传统的，“文档”式的网页，互联网的原始形态，只是内容的组织形式和传播手段，对于多数网页来说，内容才是根本，JS只是锦上添花，或者说是调料，最重要的是保证内容的完整语义，可访问性，以及适应过去/现在/未来的多种平台的能力。但是，除了“文档”类型的网页，现在也开始兴起大量的&#8221;web应用&#8221;，它们是在线的服务，也是在线的软件，对它们来说，浏览器是一个容器，网页是一种界面呈现方式，数据是异步获取的，频繁变化的，而且是细粒度的（比如并非一篇完整的文章，而是一若干来自数据库的字段），虽然同样以内容为中心，但是在这个语境里，“内容”是指纯粹的数据，而并非整块整块的HTML，一旦缺少了界面的交互功能，缺少了JS程序的支持，数据根本就无法呈现，也就根本不具备访问这些应用的条件，对于这种类型的网页来说，“预留退路”并非是不可侵犯的信条。
更多情况下，网页是复合的，会同时包含文档和软件应用的特点，于是就应该有选择的采纳那些适用于自己的原则，比如把JS和CSS与内容有效的分离，兼容多种平台，保证核心内容能被搜索引擎抓取，等等。
有一个很好的例子是土豆网的播放页，这是在土豆网全站当中，最重要同时也是web应用特征所占比例最大的页面之一，javascript和flashplayer对它来说是必不可少的基础运行环境，所以你可以看到它的html设计跟其他页面有很大差别：

script标签出现在html顶部——在其他网页里，我们习惯把css放在顶部，js放在底部，让页面先呈现，之后再附加行为，但是在播放页面里，播放器是最重要的内容，播放器加载的速度是最关键的用户体验。
HTML里会包含JS代码——只有一处，就是TUI.player.load，理由同样是为了保证播放器加载速度这个核心用户体验，不得不祭出document.write这种“非常不提倡”的必杀技来写入flash元素
有大量内容通过AJAX获取——比如评论，还有侧栏里的某些模块。因为它们是分离的数据，并非主要内容
没有使用正常的流式布局——player和toolbar都是脱离文档的独立区域，采用绝对定位
侧栏上的视频截图并没有把原始文件地址放在src属性里——延迟加载，如果不拖动滚动条，很多图片就不会无意义的下载

但是在很多方面同样也要做到Unobtrusive：

对于核心内容，比如视频信息，作者信息，都是遵循文档式网页的设计原则，对搜索引擎友好
在豆单播放页里，播放器下面的界面列表虽然是一个界面元素，但是也应该包含在文档的语义中，所以采用html的UL/LI来实现


第二个局限性是：这些原则早晚会过时。以前WaSP成员们千辛万苦推广这些观念的时候，互联网上到处都是惨不忍睹的网页，建立标准和规范，进行观念的革新，这些需求胜过了对技术的应用，而现在web标准早已普及，web应用需要进一步发展。以前Douglas Crockford，PPK在传道的时候，国外的网站还必须支持ie5.5甚至5.0之类的浏览器，恶劣的环境让web设计者和开发者们必须自我约束JS的使用，避免形成门槛。而现在，ie6在国外的占有率已经开始低于firefox（20%），很多网站已经开始放弃对ie6的支持，google和yahoo也在引导用户替换ie6。刚才我提到过，通过各种移动设备访问web的用户正在迅速增多，而这些设备对JS的支持不一致，但是这就像桌面电脑上的发展过程一样，同样是一个暂时现象，随着webkit变成iphone，android，palm pre这些新平台的统一标准，Mozilla也在积极把XUL技术应用到移动平台，环境的变化其实比桌面电脑要快的多。
我认为Graceful Degradation，Progressive Enhancement，Unobtrusive JavaScript这类东西都不适合过度的鼓吹，它们只是基础概念，是在特定时期特定环境中形成的经验和指导，而不应该是束缚前端开发人员和产品设计人员的教条，实际上，这些保守的观念来自技术的局限，而技术的局限不是我们逃避使用技术的理由，相反，我们可以仍然使用技术来打破这些局限，我们需要的是像ie7.js，excanvas.js，jquery.js这样的解决方案，而不是在开发中畏首畏尾，把每个前端开发者都教唆成原教旨主义者（上次我们公司的小麦对我说：前端开发都有这种倾向……我要说这是历史遗留的伤痕，将在世代中流传下去……）

================吐槽结束的分割线================

最后回复两个邮件里的问题……
关于用户的统计数据，土豆网是有的，可以想象由于多数用户比较大众和小白，IE6的比例相当高，比较冏的是，腾讯TT的比例也很高，等同于Firefox，我必须说它那种跟QQ绑定在一起，经常无意中启动，启动之后就设置为默认浏览器的套路，确实很强大……在普通用户当中，“默认”是强大的力量，默认的通常就是最熟悉的，最熟悉的就是最好的……不过，统计数据有时并不能真正反映出用户数量，比如Opera用户在你的统计数据里只占到0.01%，你就要思考一下究竟是Opera用户确实只有这么多，还是你的网站对Opera支持太差，导致人家都不来……
关于我的blog……其实我很早就计划重做这个blog了，现在的版本是一年半前的，从技术上来说很幼稚，我都懒得优化和修补了……但是，即使重做，我仍然不会把别人的“用户体验”放在第一位，就像侧栏里说明的那样：“优先满足个人喜好”。blog有很多类型，有的是个人媒体，有的是文集，有的是日记，有的是个性化空间，而我想要的blog是“个人信息聚合”，除了满足阅读的需求，必然还要包含大量个性化内容，也就是说，用户首先是我，其次才是读者和我的好友，而对于阅读者来说，浏览方式不止一种，比如我自己就更习惯用google reader来阅读blog，如果用户愿意选择网页形式来访问，就会被强加很多个性化内容，桀桀桀，喜欢的继续看，不喜欢的关掉页面离开，这也算双向选择罢……
]]></description>
			<content:encoded><![CDATA[<p><a href='http://www.limboy.com/wp-content/uploads/2009/01/cloudbook.jpg' title='cloudbook.jpg'><img src='http://www.limboy.com/wp-content/uploads/2009/01/cloudbook.jpg' alt='cloudbook.jpg' style="border:0;float:left;margin:0 5px 5px 0;width:200px;" /></a>早上收到一封邮件，问的正好是我一直如哽在喉的事情：</p>
<p><em style="display:block">对于web开发中的预留退路问题，我一直犹豫不决。在安全方面，自然是不能完全相信JavaScript，这点是确定的。但在用户体验方面，是否真的需要处处&#8221;预留退路&#8221;，照顾那些不支持JS或者对JS支持不好的用户吗？而UED工程师们又一直在说，不&#8221;预留退路&#8221;会惹恼数量不少的用户，但却从没有人提起具体会是多少用户、多少比例。不知道YY大神手里有这方面的数据吗？记得YY您在建立Limbo混沌海的时候，就选择了&#8221;不预留退路&#8221;的方式，不知当初又是出于什么原因这样考虑的呢？非常想听听您对&#8221;预留退路&#8221;问题的看法，期待您的回信。</em><br />
<span id="more-216"></span><br />
这种设计观念，或者说原则，不管它叫什么名字，比如“预留退路”/“平稳退化”（Graceful Degradation），“渐进增强”（Progressive Enhancement），“不唐突的javascript”（Unobtrusive JavaScript）……从UE的角度来说是非常重要的，它的重要性不仅仅来自“有多少比例的用户不开启javascript支持”，而是因为如今访问web的方式正在变的越来越丰富多样，平板电脑（Tablet PC），上网本（netbook），掌上电脑（UMPC/MID），手机，iphone/ipod touch，这些平台有完全不同的性能，屏幕尺寸，浏览器，和操作方式，它们对javascript的支持也可能不一致（比如我以前抱怨过<a target="_blank" href="http://www.limboy.com/2008/03/08/iphone-app-develop/">iphone的差别</a>）。很多“严肃”的网站还需要考虑到<a target="_blank" href="http://www.junchenwu.com/WAI/wai-pageauth.html">“可访问性”（Accessibility）</a>，要保证能支持屏幕阅读器之类的设备，让那些有视觉缺陷的用户也可以无障碍的使用。此外还有语义网方面的要求，随着web2.0带来的海量信息，互联网也在向一台超级计算机的方向发展，需要靠网络本身去处理网络上的信息，而不是靠人的肉眼去一张网页一张网页的识别，现在的网页不仅仅是供人阅读，同样也需要面向机器，所以不能因为javascript的使用而影响到内容，让机器无法抓取和识别。</p>
<p>不过，以上这些观念有两方面的局限性：<br />
<br/></p>
<p>第一，它们仅仅适用于传统的，“文档”式的网页，互联网的原始形态，只是内容的组织形式和传播手段，对于多数网页来说，内容才是根本，JS只是锦上添花，或者说是调料，最重要的是保证内容的完整语义，可访问性，以及适应过去/现在/未来的多种平台的能力。但是，除了“文档”类型的网页，现在也开始兴起大量的&#8221;web应用&#8221;，它们是在线的服务，也是在线的软件，对它们来说，浏览器是一个容器，网页是一种界面呈现方式，数据是异步获取的，频繁变化的，而且是细粒度的（比如并非一篇完整的文章，而是一若干来自数据库的字段），虽然同样以内容为中心，但是在这个语境里，“内容”是指纯粹的数据，而并非整块整块的HTML，一旦缺少了界面的交互功能，缺少了JS程序的支持，数据根本就无法呈现，也就根本不具备访问这些应用的条件，对于这种类型的网页来说，“预留退路”并非是不可侵犯的信条。</p>
<p>更多情况下，网页是复合的，会同时包含文档和软件应用的特点，于是就应该有选择的采纳那些适用于自己的原则，比如把JS和CSS与内容有效的分离，兼容多种平台，保证核心内容能被搜索引擎抓取，等等。</p>
<p>有一个很好的例子是<a target="_blank" href="http://www.tudou.com/playlist/playindex.do?lid=4888295">土豆网的播放页</a>，这是在土豆网全站当中，最重要同时也是web应用特征所占比例最大的页面之一，javascript和flashplayer对它来说是必不可少的基础运行环境，所以你可以看到它的html设计跟其他页面有很大差别：</p>
<ul>
<li>script标签出现在html顶部——在其他网页里，我们习惯<a target="_blank" href="http://developer.yahoo.com/performance/rules.html#js_bottom">把css放在顶部，js放在底部</a>，让页面先呈现，之后再附加行为，但是在播放页面里，播放器是最重要的内容，播放器加载的速度是最关键的用户体验。</li>
<li>HTML里会包含JS代码——只有一处，就是TUI.player.load，理由同样是为了保证播放器加载速度这个核心用户体验，不得不祭出document.write这种“非常不提倡”的必杀技来写入flash元素</li>
<li>有大量内容通过AJAX获取——比如评论，还有侧栏里的某些模块。因为它们是分离的数据，并非主要内容</li>
<li>没有使用正常的流式布局——player和toolbar都是脱离文档的独立区域，采用绝对定位</li>
<li>侧栏上的视频截图并没有把原始文件地址放在src属性里——延迟加载，如果不拖动滚动条，很多图片就不会无意义的下载</li>
</ul>
<p>但是在很多方面同样也要做到Unobtrusive：</p>
<ul>
<li>对于核心内容，比如视频信息，作者信息，都是遵循文档式网页的设计原则，对搜索引擎友好</li>
<li>在豆单播放页里，播放器下面的界面列表虽然是一个界面元素，但是也应该包含在文档的语义中，所以采用html的UL/LI来实现</li>
</ul>
<p><br/></p>
<p>第二个局限性是：这些原则早晚会过时。以前<a target="_blank" href="http://www.webstandards.org/">WaSP</a>成员们千辛万苦推广这些观念的时候，互联网上到处都是惨不忍睹的网页，建立标准和规范，进行观念的革新，这些需求胜过了对技术的应用，而现在web标准早已普及，web应用需要进一步发展。以前Douglas Crockford，PPK在传道的时候，国外的网站还必须支持ie5.5甚至5.0之类的浏览器，恶劣的环境让web设计者和开发者们必须自我约束JS的使用，避免形成门槛。而现在，ie6在国外的占有率已经开始<a target="_blank" href="http://ajaxian.com/archives/i-wont-support-ie-6-in-2009">低于firefox（20%）</a>，很多网站已经开始<a href="http://www.infoq.com/cn/news/2008/07/ie6_on_its_way_out">放弃对ie6的支持</a>，google和yahoo也在引导用户替换ie6。刚才我提到过，通过各种移动设备访问web的用户正在迅速增多，而这些设备对JS的支持不一致，但是这就像桌面电脑上的发展过程一样，同样是一个暂时现象，随着webkit变成iphone，android，palm pre这些新平台的统一标准，Mozilla也在积极<a target="_blank" href="http://arstechnica.com/news.ars/post/20081224-mozilla-releases-second-alpha-of-fennec-mobile-browser.html">把XUL技术应用到移动平台</a>，环境的变化其实比桌面电脑要快的多。</p>
<p>我认为Graceful Degradation，Progressive Enhancement，Unobtrusive JavaScript这类东西都不适合过度的鼓吹，它们只是基础概念，是在特定时期特定环境中形成的经验和指导，而不应该是束缚前端开发人员和产品设计人员的教条，实际上，这些保守的观念来自技术的局限，而技术的局限不是我们逃避使用技术的理由，相反，我们可以仍然使用技术来打破这些局限，我们需要的是像<a target="_blank" href="http://code.google.com/p/ie7-js/">ie7.js</a>，<a target="_blank" href="http://excanvas.sourceforge.net/">excanvas.js</a>，jquery.js这样的解决方案，而不是在开发中畏首畏尾，把每个前端开发者都教唆成原教旨主义者（上次我们公司的小麦对我说：前端开发都有这种倾向……我要说这是历史遗留的伤痕，将在世代中流传下去……）<br />
<br/><br />
================吐槽结束的分割线================<br />
<br/><br />
最后回复两个邮件里的问题……</p>
<p>关于用户的统计数据，土豆网是有的，可以想象由于多数用户比较大众和小白，IE6的比例相当高，比较冏的是，腾讯TT的比例也很高，等同于Firefox，我必须说它那种跟QQ绑定在一起，经常无意中启动，启动之后就设置为默认浏览器的套路，确实很强大……在普通用户当中，“默认”是强大的力量，默认的通常就是最熟悉的，<a target="_blank" href="http://www.ruanyifeng.com/blog/2009/01/font_smoothing_anti-aliasing_and_sub-pixel_rendering.html">最熟悉的就是最好的</a>……不过，统计数据有时并不能真正反映出用户数量，比如Opera用户在你的统计数据里只占到0.01%，你就要思考一下究竟是Opera用户确实只有这么多，还是你的网站对Opera支持太差，导致人家都不来……</p>
<p>关于我的blog……其实我很早就计划重做这个blog了，现在的版本是一年半前的，从技术上来说很幼稚，我都懒得优化和修补了……但是，即使重做，我仍然不会把别人的“用户体验”放在第一位，就像侧栏里说明的那样：“优先满足个人喜好”。blog有很多类型，有的是个人媒体，有的是文集，有的是日记，有的是个性化空间，而我想要的blog是“个人信息聚合”，除了满足阅读的需求，必然还要包含大量个性化内容，也就是说，用户首先是我，其次才是读者和我的好友，而对于阅读者来说，浏览方式不止一种，比如我自己就更习惯用google reader来阅读blog，如果用户愿意选择网页形式来访问，就会被强加很多个性化内容，桀桀桀，喜欢的继续看，不喜欢的关掉页面离开，这也算双向选择罢……</p>
]]></content:encoded>
			<wfw:commentRss>http://www.limboy.com/2009/01/20/is_javascript_need_degradation/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>jQuery1.3和里程碑式的新选择器引擎</title>
		<link>http://www.limboy.com/2009/01/15/jquery13_new_selector_engine_sizzle/</link>
		<comments>http://www.limboy.com/2009/01/15/jquery13_new_selector_engine_sizzle/#comments</comments>
		<pubDate>Wed, 14 Jan 2009 19:27:48 +0000</pubDate>
		<dc:creator>Dexter.Yy</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[代码]]></category>

		<guid isPermaLink="false">http://www.limboy.com/2009/01/15/jquery13_new_selector_engine_sizzle/</guid>
		<description><![CDATA[John Resig老爷在twitter上宣布jQuery1.3正式发布，直接把2加到3反映了这个版本的重要性不同以往，除了重写很多重要方法——比如offset（获取页面上的各种尺寸和位置数据），创建和插入DOM节点（比如append, before之类，这些方法是JQuery以前速度上的瓶颈之一，我就完全不用它们，但是现在速度提高了6倍）——最重要的改变是启用了全新的Sizzle引擎来实现CSS选择器。
从“JQuery”这个名字就能看出，用CSS/XML选择器查询页面元素，是这个javascript库赖以起家的绝活，最早可以追溯到Dean Edwards的cssQuery，和Simon Willison的getElementsBySelector，但是在那个上古时代（史料记载中无正式名称，我们可以称之为“Age of the First Bubble”，或者“DHTML Era”，虽然也有学者认为希腊神话中描述的黑铁时代（Iron Age）就是指那段时间……dojo创始人Alex Russell，以及prototype创始人Sam Stephenson，都是来自那个时代地淫～），面对恶劣的浏览器环境和粗糙的web应用，这些选择器的实现只能被当作geek的实验，没有应用市场。而到了05年，世界已经进入web2.0和ajax的新纪元，84年出生的天才少年John Resig（555跟我同年~>_]]></description>
			<content:encoded><![CDATA[<p><a href='http://www.limboy.com/2009/01/15/jquery13_new_selector_engine_sizzle/rockstarjpg/' rel='attachment wp-att-211' title='rockstar.jpg'><img src='http://www.limboy.com/wp-content/uploads/2009/01/rockstar.jpg' alt='rockstar.jpg' style="border:0;float:left;margin:0 10px 0 0;" /></a>John Resig老爷在<a href="http://twitter.com/jeresig/status/1118348417" target="_blank">twitter</a>上宣布jQuery1.3正式发布，直接把2加到3反映了这个版本的重要性不同以往，除了重写很多重要方法——比如offset（获取页面上的各种尺寸和位置数据），创建和插入DOM节点（比如append, before之类，这些方法是JQuery以前速度上的瓶颈之一，我就完全不用它们，但是现在速度提高了6倍）——最重要的改变是启用了全新的Sizzle引擎来实现CSS选择器。</p>
<p>从“JQuery”这个名字就能看出，用CSS/XML选择器查询页面元素，是这个javascript库赖以起家的绝活，最早可以追溯到Dean Edwards的<a target="_blank" href="http://dean.edwards.name/my/cssQuery/">cssQuery</a>，和Simon Willison的<a target="_blank" href="http://simonwillison.net/2003/Mar/25/getElementsBySelector/">getElementsBySelector</a>，但是在那个上古时代（史料记载中无正式名称，我们可以称之为“Age of the First Bubble”，或者“DHTML Era”，虽然也有学者认为希腊神话中描述的黑铁时代（Iron Age）就是指那段时间……dojo创始人<a target="_blank" href="http://alex.dojotoolkit.org/">Alex Russell</a>，以及prototype创始人<a target="_blank" href="http://conio.net/">Sam Stephenson</a>，都是来自那个时代地淫～），<span id="more-210"></span>面对恶劣的浏览器环境和粗糙的web应用，这些选择器的实现只能被当作geek的实验，没有应用市场。而到了05年，世界已经进入web2.0和ajax的新纪元，84年出生的天才少年John Resig（555跟我同年~>_<~）在先行者的启发下（必须承认D Edwards老爷“启发”了很多人……自己的作品却没机会进入主流）开始探索选择器技术，一年后的1月15日（没错今天是jQuery三周年生日）就在<a target="_blank" href="http://ejohn.org/blog/barcampnyc-wrap-up/">纽约的Barcamp</a>上正式发布了第一版的JQuery，迅速红遍全球，流行程度堪比摇滚巨星（我就很喜欢JQuery去年发布1.2.6时搞得那个<a target="_blank" href="http://farm4.static.flickr.com/3026/2809148861_45a9c46390_o.png">摇滚主题的主页</a>哑！）<img src='http://www.limboy.com/wp-content/uploads/2009/01/jquery-logo.gif' alt='jquery-logo.gif' style="border:0;margin:0;float:right;" /></p>
<p>在JQuery的影响下，选择器逐渐变成了javascript开发的主流需求，其他的库不进则死，都匆匆引入选择器，比如dojo.query，YAHOO.util.Selector.query，$$……甚至各大浏览器厂商也开始实现W3C最新的<a target="_blank" href="http://www.w3.org/TR/selectors-api/">Selectors API标准</a>（包括Safari3.1、Firefox3.1、IE8 beta，居然连IE也实现了耶！可见这个现象的反常程度……）</p>
<p>但是当选择器的实现变得无处不在五花八门的时候（我以前做的<a target="_blank" href="http://www.limboy.com/2008/05/31/yyopml-release/">JQuery迷你版</a>里也有一个自己实现的选择器-___-b），开发者们又有了新烦恼，他们需要统一的，能平稳迁移/升级的接口，需要最高效的实现，随着W3C Selectors API的实现，统一标准也变得更加重要和紧迫，于是John Resig就像武林盟主一样站出来开发了一个纯粹而高效的选择器引擎——<a target="_blank" href="http://github.com/jeresig/sizzle/">Sizzle</a>，并主动贡献给<a target="_blank" href="http://ajaxian.com/archives/a-great-example-of-sharing-sizzle-engine-in-dojo-foundation">prototype, dojo, Mochkit等各大门派</a>，jQuery1.3是第一个采用Sizzle的正式产品，可以看到速度有<a target="_blank" href="http://docs.jquery.com/Release:jQuery_1.3#Performance">显著的提升</a>，今后的发展非常令人期待。</p>
<p>Sizzle反映了一种新趋势，随着javascript库的逐渐成熟，一些功能开始被分离出来设计成独立维护的引擎/核心。实际上现在的主流库里，有很多代码都互相借鉴，并采纳blogsphere里讨论出的最新最好的实现方法，比如jQuery的DOM Ready方法就可以明显看到这种演进，而那些涉及跨浏览器的实现和bug fix，尤其容易趋向于统一。有机会产生通用引擎的领域，除了css选择器，可以预见的还有2D/3D绘图引擎（封装canvas,VML或SVG），模板引擎，对象映射，文本解析，动画，运动和定位相关的计算，还有一些基础代码，比如迭代器。</p>
<p>不过关于选择器，还有一点必须指出的是，无论选择器发展的多么高效，即使有一天能完全当作native实现来对待，也不能过度的依赖它来完成任务，满足于写一些脚本式的代码，而忽视javascript语言本身的算法，数据结构和模式。这个道理其实就类似php和mysql的关系，php作为服务器端专业的web开发语言，有大量开发工作是围绕着数据来进行，而强大的mysql已经实现很多针对数据查询的算法和逻辑，加上php本身与其说是一门语言，不如说是工具包，导致很多初心的php程序员简单的依赖于mysql，编程能力普遍不高，进而损害到了php程序员的平均工资……</p>
<p>从这个角度上来讲，javascript跟php非常相像，虽然javascript本身是一门强悍而集大成的语言（记得上次去帝都参加SD2C时，<a target="_blank" href="http://www.sd2china2008.com/track2#a28">天际网的CTO郭应寿</a>说“喜欢技术的人不可能不喜欢javascript”），但是多数时候都被限制在浏览器的sandbox里，曾经一度沦为真正的“脚本语言”，多亏浏览器后来施舍了DOM和xhr，才让javascript有了用武之地，所以js在很大程度上也是围绕着DOM在编程，DOM是前端最重要的数据结构，有了强大的选择器工具，很多需求只要反复调用选择器，写几串脚本式的代码就能实现，如果满足于这种开发方式，不站在更高的角度去设计和构建应用，对于自己和自己的工作都可以说是非常危险的。</p>
<p>另外，设计良好的html，重要性相当于后端的数据库设计，可以让选择器的使用变得更高效，并直接影响js的设计模式。我在一些项目中非常喜欢这样的理念：在保证语义和简洁的前提下，让HTML成为一种配置文件，当需求有变化，或是在一些可复用的场合，只需要简单的编写html，就能自动实现相应的程序逻辑。对于选择器的使用，还存在另一种截然相反的设计方式：在有些情况下，需要让javascript和html尽可能的解耦合，让同样的代码可以适应灵活变化的html结构，并尽可能减少dom操作，具体的例子会在下篇文章中给出。</p>
<p>其实本来今天最想写的是jQuery1.3中新增的Live Events，因为土豆网全局js里正好有一个自己实现的方法$.fn.eventProxy，两者基于同样的设计模式，明天有空的时候再写算了，这篇就当作向三岁的JQuery致敬。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.limboy.com/2009/01/15/jquery13_new_selector_engine_sizzle/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>iframe和异步的跨域请求，结合土豆网的实例</title>
		<link>http://www.limboy.com/2008/12/31/iframe-cross-site-request/</link>
		<comments>http://www.limboy.com/2008/12/31/iframe-cross-site-request/#comments</comments>
		<pubDate>Tue, 30 Dec 2008 19:00:46 +0000</pubDate>
		<dc:creator>Dexter.Yy</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[代码]]></category>
		<category><![CDATA[土豆网]]></category>

		<guid isPermaLink="false">http://www.limboy.com/2008/12/31/iframe-cross-site-request/</guid>
		<description><![CDATA[这篇文章将会探讨一下在网页里做异步的跨域请求，以及借助iframe来获取数据的方法。
呃，本来我觉得这个话题没什么好说的了，因为如今好像没有几个web应用能离开这类request，google和facebook用iframe来做comet的时候也基本上把能hack的都hack遍了，所以我估计开发者社区里应该早就形成所谓的&#8221;最佳实践&#8221;（best practices）了罢。不过最近看到有一些关注前端技术的blog（比如realazy）在讨论相关的话题，发现还是有一些东西值得写下来。

一、借助script的异步跨域请求
先说跨域的问题，首先要指出的是，iframe里的js宿主对象一样也躲不开同源策略（Same Origin Policy），仅仅能解决二级域名的跨域而已，比如www.tudou.com和so.tudou.com，如果要请求某个八杆子打不到一起去的域名下的数据（例如你想搞mashup），建议老老实实的用script标签去请求JSONP罢。关于JSONP要附带说一下的是，jQuery对JSONP请求的封装方式很值得提倡：
$.getJSON(url, params + &#34;&#38;jsoncallback=?&#34;, function(json){
&#160; &#160; /* do something */
});
用jsoncallback作为服务器端支持的标准jsonp参数，而每次执行这个方法都会用时间戳生成一个唯一的全局函数名，替换这个“?”，这个细节被封装到黑盒里，使用者不必了解，可以像普通的ajax请求一样，用匿名的回调函数作为最末尾的参数（这是jquery强调的风格），这种语法糖（syntactic sugar）的作用绝对不仅仅是让前端开发人员可以偷懒而已，对代码的可读性，兼容性和今后的维护都有好处。（我经常要向服务器端的开发人员解释这个道理，否则他们才不给你支持什么jsoncallback参数呢，直接给你返回一个“yy({……})”就算完工……囧）
二、利用前沿技术的跨域方法
当然了，我们还可以走一些目前来看比较野的路子来实现跨域，比如在页面里嵌入一个不到1K的swf，借助flashplayer向部署了crossdomain.xml的服务器请求数据，再用actionscript里的ExternalInterface类把数据还给javascript（我觉得这种方法忒有调用dll的感觉～大心）。
我们还可以指望ie8里支持的XDomainRequestAllowed，和firefox3.1支持的Access Control，甚至传说中的HTML5 socket……噢喔喔，多么甜美的梦……/掐一把脸蛋
三、用iframe直接发送跨域请求
跟script标签一样，iframe也可以用来替代ajax，而且在修改document.domain之后（比如上面提到的两个域名，可以设置document.domain = &#8220;tudou.com&#8221;），还可以解决部分跨域问题。
通过iframe请求数据的方法，最直接的莫过于在页面里动态的嵌入一个iframe标签，用它的src属性直接请求包含数据的网页，然后利用那个网页里的js把数据传给父页面，比如：
&#60;iframe id=&#34;crossdomain&#34; width=&#34;0&#34; height=&#34;0&#34; style=&#34;visibility:hidden;&#34; src=&#34;http://yoursite.com/request_url/&#34; &#62;&#60;/iframe&#62;
这种方法耦合的太紧，非常不推荐。你请求的URI代表一个资源，应该是单纯的数据，它会作为xml，json，js代码还是html来处理，这个并不重要，不应该把你的程序逻辑跟数据混杂到一起，数据也不应该因为跨域或不跨域，用iframe，script还是ajax来请求就变成完全不同的东西。
有人会说：为了让数据能够被JS处理，返回的内容难免有差异。——但是小的差异可以通过合理的封装隐藏起来，比如JQuery的getJSON方法
有人会说：请求的URI是一个动态页面，同样可以在URI里支持类似jsoncallback的参数，生成一个script标签和其中的JS代码，把数据“包裹”在JS里，比如请求“http://yoursite.com/request_url/?callback=cb1304344”，返回：
&#60;script type=&#34;text/javascript&#34;&#62;
document.domain=&#34;tudou.com&#34;;
top.cb1304344({ /* 数据 */ });
&#60;/script&#62;
——首先，很多情况下你请求到的不会是动态页面，在这个到处都强调高负载的web世界里，你拿到的经常是squid之类的代理程序返回的缓存。其次，如果你请求的是HTML格式的文本，为了能作为JS代码来执行，服务器端必须对这段文本做转义和清理工作，而且安全性还不一定能保证（因为HTML里经常包含很多来自UGC的内容），如果你请求的是JSON格式的数据……那何必用iframe咧……直接嵌script罢……
四、用iframe直接请求数据的最佳实践
我推荐在上述方法的基础上做改良，首先在服务器端，直接返回数据本身，并且把数据“包裹”在一个textarea标签里，比如：
&#60;textarea&#62;&#60;div&#62;&#60;p&#62;yyyyy&#60;/p&#62;&#60;/div&#62;&#60;/textarea&#62;
textarea的优点是可以支持任何格式的内容，而且这些内容不会在iframe子页面里解析（比如创建DOM树，执行JS），接下来前端要做的，只是在父页面里获取到子页面的DOM，把textarea的内容取出来（注意不能取innerHTML而要取value）。
这里存在一个判断iframe是否加载完成的问题，解决方法之一是在iframe标签上写onload事件，不过这样就需要显式的调用一个函数。
方法二如下：
(function(){
try{
&#160; &#160; callback(document.getElementById('crossdomain').contentWindow.document.body.getElementsByTagName(&#34;TEXTAREA&#34;)[0].value);
}catch(e){
&#160; &#160; setTimeout(arguments.callee,0);
&#160; &#160; return;
}&#160; &#160; 
})();
最后我们可以封装出这样一个方法：
window.TUI = window.$ = {};
/**
 * @public 通过iframe异步请求数据
 * @param {string}&#160; url是请求的地址
 * @param {function}&#160; cb是处理返回数据的回调函数
 */
TUI.getIframeData = function(url, [...]]]></description>
			<content:encoded><![CDATA[<p><a href='http://www.limboy.com/wp-content/uploads/2008/12/tudou_frame.jpg' title='tudou_frame.jpg'><img style="float:left;width:200px;margin:0 10px 10px 0;" src='http://www.limboy.com/wp-content/uploads/2008/12/tudou_frame.jpg' alt='tudou_frame.jpg' /></a>这篇文章将会探讨一下在网页里做异步的跨域请求，以及借助iframe来获取数据的方法。</p>
<p>呃，本来我觉得这个话题没什么好说的了，因为如今好像没有几个web应用能离开这类request，google和facebook用iframe来做comet的时候也基本上把能hack的都hack遍了，所以我估计开发者社区里应该早就形成所谓的&#8221;最佳实践&#8221;（best practices）了罢。不过最近看到有一些关注前端技术的blog（比如<a target="_blank" href="http://realazy.org/blog/2008/11/30/benifit-of-fecthing-page-via-iframe/">realazy</a>）在讨论相关的话题，发现还是有一些东西值得写下来。<span id="more-208"></span></p>
<p><br/></p>
<h3>一、借助script的异步跨域请求</h3>
<p>先说跨域的问题，首先要指出的是，iframe里的js宿主对象一样也躲不开同源策略（Same Origin Policy），仅仅能解决二级域名的跨域而已，比如www.tudou.com和so.tudou.com，如果要请求某个八杆子打不到一起去的域名下的数据（例如你想搞mashup），建议老老实实的用script标签去请求<a href="http://bob.pythonmac.org/archives/2005/12/05/remote-json-jsonp/" target="_blank">JSONP</a>罢。关于JSONP要附带说一下的是，jQuery对JSONP请求的封装方式很值得提倡：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Gray;">$.</span><span style="color: Blue;">getJSON</span><span style="color: Olive;">(</span><span style="color: Blue;">url</span><span style="color: Gray;">, </span><span style="color: Blue;">params</span><span style="color: Gray;"> + </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">&amp;jsoncallback=?</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">json</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: #ffa500;">/* do something */</span></li>
<li><span style="color: Olive;">})</span><span style="color: Gray;">;</span></li></ol></div>
<p>用jsoncallback作为服务器端支持的标准jsonp参数，而每次执行这个方法都会用时间戳生成一个唯一的全局函数名，替换这个“?”，这个细节被封装到黑盒里，使用者不必了解，可以像普通的ajax请求一样，用匿名的回调函数作为最末尾的参数（这是jquery强调的风格），这种语法糖（syntactic sugar）的作用绝对不仅仅是让前端开发人员可以偷懒而已，对代码的可读性，兼容性和今后的维护都有好处。（我经常要向服务器端的开发人员解释这个道理，否则他们才不给你支持什么jsoncallback参数呢，直接给你返回一个“yy({……})”就算完工……囧）</p>
<h3>二、利用前沿技术的跨域方法</h3>
<p>当然了，我们还可以走一些目前来看比较野的路子来实现跨域，比如在页面里嵌入一个不到1K的swf，借助flashplayer向部署了crossdomain.xml的服务器请求数据，再用actionscript里的ExternalInterface类把数据还给javascript（我觉得这种方法忒有调用dll的感觉～大心）。</p>
<p>我们还可以指望ie8里支持的<a target="_blank" href="http://code.msdn.microsoft.com/Release/ProjectReleases.aspx?ProjectName=ie8whitepapers&#038;ReleaseId=581">XDomainRequestAllowed</a>，和firefox3.1支持的<a target="_blank" href="http://dev.w3.org/2006/waf/access-control/">Access Control</a>，甚至传说中的<a target="_blank" href="http://www.reddit.com/r/programming/comments/7a3rc/html_5_websocket_is_neither_web_nor_socket/">HTML5 socket</a>……噢喔喔，多么甜美的梦……/掐一把脸蛋</p>
<h3>三、用iframe直接发送跨域请求</h3>
<p>跟script标签一样，iframe也可以用来替代ajax，而且在修改document.domain之后（比如上面提到的两个域名，可以设置document.domain = &#8220;tudou.com&#8221;），还可以解决部分跨域问题。</p>
<p>通过iframe请求数据的方法，最直接的莫过于在页面里动态的嵌入一个iframe标签，用它的src属性直接请求包含数据的网页，然后利用那个网页里的js把数据传给父页面，比如：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Olive;">&lt;</span><span style="color: Green;">iframe</span><span style="color: Gray;"> </span><span style="color: #00008b;">id</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">crossdomain</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: #00008b;">width</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">0</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: #00008b;">height</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">0</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: #00008b;">style</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">visibility:hidden;</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: #00008b;">src</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">http://yoursite.com/request_url/</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: Olive;">&gt;&lt;/</span><span style="color: Green;">iframe</span><span style="color: Olive;">&gt;</span></li></ol></div>
<p>这种方法耦合的太紧，非常不推荐。你请求的URI代表一个资源，应该是单纯的数据，它会作为xml，json，js代码还是html来处理，这个并不重要，不应该把你的程序逻辑跟数据混杂到一起，数据也不应该因为跨域或不跨域，用iframe，script还是ajax来请求就变成完全不同的东西。</p>
<p>有人会说：为了让数据能够被JS处理，返回的内容难免有差异。——但是小的差异可以通过合理的封装隐藏起来，比如JQuery的getJSON方法</p>
<p>有人会说：请求的URI是一个动态页面，同样可以在URI里支持类似jsoncallback的参数，生成一个script标签和其中的JS代码，把数据“包裹”在JS里，比如请求“http://yoursite.com/request_url/?callback=cb1304344”，返回：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Olive;">&lt;</span><span style="color: Green;">script</span><span style="color: Gray;"> </span><span style="color: #00008b;">type</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">text/javascript</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">&gt;</span></li>
<li><span style="color: Gray;">document.domain=&quot;tudou.com&quot;;</span></li>
<li><span style="color: Gray;">top.cb1304344({ /* 数据 */ });</span></li>
<li><span style="color: Olive;">&lt;/</span><span style="color: Green;">script</span><span style="color: Olive;">&gt;</span></li></ol></div>
<p>——首先，很多情况下你请求到的不会是动态页面，在这个到处都强调高负载的web世界里，你拿到的经常是<a target="_blank" href="http://blog.s135.com/book/squid/">squid</a>之类的代理程序返回的缓存。其次，如果你请求的是HTML格式的文本，为了能作为JS代码来执行，服务器端必须对这段文本做转义和清理工作，而且安全性还不一定能保证（因为HTML里经常包含很多来自UGC的内容），如果你请求的是JSON格式的数据……那何必用iframe咧……直接嵌script罢……</p>
<h3>四、用iframe直接请求数据的最佳实践</h3>
<p>我推荐在上述方法的基础上做改良，首先在服务器端，直接返回数据本身，并且把数据“包裹”在一个textarea标签里，比如：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Olive;">&lt;</span><span style="color: Green;">textarea</span><span style="color: Olive;">&gt;&lt;</span><span style="color: Green;">div</span><span style="color: Olive;">&gt;&lt;</span><span style="color: Green;">p</span><span style="color: Olive;">&gt;</span><span style="color: Gray;">yyyyy</span><span style="color: Olive;">&lt;/</span><span style="color: Green;">p</span><span style="color: Olive;">&gt;&lt;/</span><span style="color: Green;">div</span><span style="color: Olive;">&gt;&lt;/</span><span style="color: Green;">textarea</span><span style="color: Olive;">&gt;</span></li></ol></div>
<p>textarea的优点是可以支持任何格式的内容，而且这些内容不会在iframe子页面里解析（比如创建DOM树，执行JS），接下来前端要做的，只是在父页面里获取到子页面的DOM，把textarea的内容取出来（注意不能取innerHTML而要取value）。</p>
<p>这里存在一个判断iframe是否加载完成的问题，解决方法之一是在iframe标签上写onload事件，不过这样就需要显式的调用一个函数。</p>
<p>方法二如下：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(){</span></li>
<li><span style="color: Green;">try</span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">callback</span><span style="color: Olive;">(</span><span style="color: Teal;">document</span><span style="color: Gray;">.</span><span style="color: Blue;">getElementById</span><span style="color: Olive;">(</span><span style="color: #8b0000;">'</span><span style="color: Red;">crossdomain</span><span style="color: #8b0000;">'</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span><span style="color: Blue;">contentWindow</span><span style="color: Gray;">.</span><span style="color: Teal;">document</span><span style="color: Gray;">.</span><span style="color: Blue;">body</span><span style="color: Gray;">.</span><span style="color: Blue;">getElementsByTagName</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">TEXTAREA</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)[</span><span style="color: Maroon;">0</span><span style="color: Olive;">]</span><span style="color: Gray;">.</span><span style="color: Blue;">value</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">}</span><span style="color: Green;">catch</span><span style="color: Olive;">(</span><span style="color: Blue;">e</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">setTimeout</span><span style="color: Olive;">(</span><span style="color: Blue;">arguments</span><span style="color: Gray;">.</span><span style="color: Blue;">callee</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">}</span><span style="color: Gray;">&nbsp; &nbsp; </span></li>
<li><span style="color: Olive;">})()</span><span style="color: Gray;">;</span></li></ol></div>
<p>最后我们可以封装出这样一个方法：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Teal;">window</span><span style="color: Gray;">.</span><span style="color: Blue;">TUI</span><span style="color: Gray;"> = </span><span style="color: Teal;">window</span><span style="color: Gray;">.$ = </span><span style="color: Olive;">{}</span><span style="color: Gray;">;</span></li>
<li><span style="color: #ffa500;">/**</span></li>
<li><span style="color: #ffa500;"> * @public 通过iframe异步请求数据</span></li>
<li><span style="color: #ffa500;"> * @param {string}&nbsp; url是请求的地址</span></li>
<li><span style="color: #ffa500;"> * @param {function}&nbsp; cb是处理返回数据的回调函数</span></li>
<li><span style="color: #ffa500;"> */</span></li>
<li><span style="color: Blue;">TUI</span><span style="color: Gray;">.</span><span style="color: Blue;">getIframeData</span><span style="color: Gray;"> = </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">url</span><span style="color: Gray;">, </span><span style="color: Blue;">cb</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">f</span><span style="color: Gray;"> = </span><span style="color: Teal;">document</span><span style="color: Gray;">.</span><span style="color: Blue;">getElementById</span><span style="color: Olive;">(</span><span style="color: #8b0000;">'</span><span style="color: Red;">crossdomain</span><span style="color: #8b0000;">'</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">if</span><span style="color: Olive;">(</span><span style="color: Blue;">f</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">f</span><span style="color: Gray;">.</span><span style="color: Blue;">src</span><span style="color: Gray;"> = </span><span style="color: Blue;">url</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">else</span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">t</span><span style="color: Gray;"> = </span><span style="color: Teal;">document</span><span style="color: Gray;">.</span><span style="color: Blue;">createElement</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">DIV</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">t</span><span style="color: Gray;">.</span><span style="color: Blue;">innerHTML</span><span style="color: Gray;"> = </span><span style="color: #8b0000;">'</span><span style="color: Red;">&lt;iframe id=&quot;crossdomain&quot; width=&quot;0&quot; height=&quot;0&quot; style=&quot;visibility:hidden;&quot; src=&quot;</span><span style="color: #8b0000;">'</span><span style="color: Gray;"> + </span><span style="color: Blue;">url</span><span style="color: Gray;"> + </span><span style="color: #8b0000;">'</span><span style="color: Red;">&quot; &gt;&lt;/iframe&gt;</span><span style="color: #8b0000;">'</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Teal;">document</span><span style="color: Gray;">.</span><span style="color: Blue;">body</span><span style="color: Gray;">.</span><span style="color: Blue;">appendChild</span><span style="color: Olive;">(</span><span style="color: Blue;">t</span><span style="color: Gray;">.</span><span style="color: Blue;">firstChild</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">try</span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">cb</span><span style="color: Olive;">(</span><span style="color: Teal;">document</span><span style="color: Gray;">.</span><span style="color: Blue;">getElementById</span><span style="color: Olive;">(</span><span style="color: #8b0000;">'</span><span style="color: Red;">crossdomain</span><span style="color: #8b0000;">'</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span><span style="color: Blue;">contentWindow</span><span style="color: Gray;">.</span><span style="color: Teal;">document</span><span style="color: Gray;">.</span><span style="color: Blue;">body</span><span style="color: Gray;">.</span><span style="color: Blue;">getElementsByTagName</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">TEXTAREA</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)[</span><span style="color: Maroon;">0</span><span style="color: Olive;">]</span><span style="color: Gray;">.</span><span style="color: Blue;">value</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Green;">catch</span><span style="color: Olive;">(</span><span style="color: Blue;">e</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">setTimeout</span><span style="color: Olive;">(</span><span style="color: Blue;">arguments</span><span style="color: Gray;">.</span><span style="color: Blue;">callee</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">&nbsp; &nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">})()</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">}</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: #ffa500;">//像这样执行</span></li>
<li><span style="color: Gray;">$.</span><span style="color: Blue;">getIframeData</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">http://yoursite.com/request_url/</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">data</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: #ffa500;">/* do something */</span></li>
<li><span style="color: Olive;">})</span><span style="color: Gray;">;</span></li></ol></div>
<p>只要再增加一个可选的param参数，这就是一个很标准的jQuery AJAX API，我们还可以在jQuery的$.get上面封装，增加一个是否跨域的判断，当这个request的URI修改成同样的域名后，自动切换到普通的AJAX方法来请求，把返回的文本用类似这样的正则/<(textarea)>(.+)<\/(textarea)>/删掉多余的字符，再传给回调函数，前端和服务器端都不用修改代码。</p>
<h3>五、用iframe直接请求数据的缺陷</h3>
<p>必须指出的是，iframe在ie里获取数据时会引发一些“小问题”，dojo的创始人Alex Russell把它们称作<a target="_blank" href="http://alex.dojotoolkit.org/2006/02/what-else-is-burried-down-in-the-depths-of-googles-amazing-javascript/">“灵异点击（phantom click）”和“噩梦般的指示器（throbber of doom）”</a>，前者是指在iframe请求内容的时候会出现一次点击链接的音效（让用户怀疑闹鬼，多差的体验口牙！），后者是指iframe加载过程中，ie的界面上会出现正在读取的提示（比如左下的进度条，右上的图标）……好罢，其实以我个人的标准，这两个问题都可以无视……</p>
<p>这种方法还有一个明显的缺陷，就是只支持GET类型的请求。</p>
<h3>六、用iframe结合ajax</h3>
<p>不过iframe还有一种使用方法，不但可以避免上面提到的问题，也不需要服务器端做任何调整，简单来说：在iframe的src里调用一个包含ajax方法的页面，然后父页面调用这个方法来发起跟子页面同域名下的ajax请求。在土豆网的播放页面上，我使用这种方法请求用户评论统一接口里的HTML内容，例如这个WH40K:DOWII的视频：</p>
<p><a  target="_blank" href="http://www.tudou.com/programs/view/iPcprDz_LhI/">http://www.tudou.com/programs/view/iPcprDz_LhI/</a></p>
<p>获得评论部分HTML的接口类似这样:</p>
<p><a  target="_blank" href=" http://comments.tudou.com/itemcomment.srv?method=get&#038;iid=21283123&#038;page=1&#038;tm=5&#038;ban=1">http://comments.tudou.com/itemcomment.srv?method=get&#038;iid=21283123&#038;page=1&#038;tm=5&#038;ban=1</a></p>
<p>这个接口在独立的一组服务器上实现，在视频播放页，豆单播放页，豆单封面，相册，个人主页都会被调用。由于包含大量用户提交的内容和复杂的HTML结构，如果用JSON形式，前端后端处理起来都效率低，此外，提交新评论，回复，删除，也会用到comments.tudou.com这个域名下的接口，而这些操作显然需要POST类型的请求。在这种需求下，借助iframe的AJAX方法</p>
<p>首先在comments.tudou.com域名下部署一个供iframe调用的跨域文件，感觉很像flashplayer的crossdomain.xml……</p>
<p><a  target="_blank" href="http://comments.tudou.com/crossdomain/index.html">http://comments.tudou.com/crossdomain/index.html</a></p>
<p>可以看到源文件里仅仅包含一个stand-alone的ajax方法……呃……你觉得很眼熟？不用怀疑，就是在jQuery源代码的基础上修改来的-___-b，支持最基本的需求。这个页面可以设置很长的过期头让浏览器缓存起来，因为不会再有变动。</p>
<p>在父页面里通过<a target="_blank" href="http://js.tudouui.com/js/comments_9.js">TUI.videoComment.request</a>提供统一的接口，不做详述了，只列举其中访问跨域方法的部分：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">try</span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; $</span><span style="color: Olive;">(</span><span style="color: #8b0000;">'</span><span style="color: Red;">#crossdomain</span><span style="color: #8b0000;">'</span><span style="color: Olive;">)[</span><span style="color: Maroon;">0</span><span style="color: Olive;">]</span><span style="color: Gray;">.</span><span style="color: Blue;">contentWindow</span><span style="color: Gray;">.</span><span style="color: Blue;">TUI</span><span style="color: Gray;">.</span><span style="color: Blue;">ajax</span><span style="color: Olive;">(</span><span style="color: Blue;">o</span><span style="color: Olive;">)</span><span style="color: Gray;">;&nbsp; &nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Green;">catch</span><span style="color: Olive;">(</span><span style="color: Blue;">e</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">setTimeout</span><span style="color: Olive;">(</span><span style="color: Blue;">arguments</span><span style="color: Gray;">.</span><span style="color: Blue;">callee</span><span style="color: Gray;">,</span><span style="color: Maroon;">500</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">&nbsp; &nbsp; </span></li>
<li><span style="color: Olive;">})()</span><span style="color: Gray;">;</span></li></ol></div>
<h3>七、总结一下</h3>
<p>iframe适用于 ( 跨域的 &#038;&#038; ( 返回大量数据 || 返回HTML内容 || 需要发POST请求 ) ) 的场合，除此之外还有<a  target="_blank" href="http://www.ibm.com/developerworks/cn/web/wa-lo-comet/">comet里的串流技术（streaming）</a>——本文不涉及。使用时需要注意保持资源的纯粹性，并尽可能隐藏那些跟其他异步请求差异很大的或包含hack的细节（比如嵌入iframe，触发回调函数，处理数据），设计出一致的，兼容性和扩展性良好的，不碍眼的接口XD</p>
<p>关于跨域还要补充一点：修改document.domain可能会产生一些无法预料的问题，比如在firefox里，document.styleSheets的cssRules属性会被拒绝访问。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.limboy.com/2008/12/31/iframe-cross-site-request/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>递归和递推：javascript求斐波那契数列的尾递归方法</title>
		<link>http://www.limboy.com/2008/11/22/javascript-tail-recursion/</link>
		<comments>http://www.limboy.com/2008/11/22/javascript-tail-recursion/#comments</comments>
		<pubDate>Sat, 22 Nov 2008 14:48:16 +0000</pubDate>
		<dc:creator>Dexter.Yy</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[代码]]></category>

		<guid isPermaLink="false">http://www.limboy.com/2008/11/23/javascript-tail-recursion/</guid>
		<description><![CDATA[刚才在IBM DW上看到这篇《JavaScript 技巧与高级特性》，其中关于arguments.callee的部分有一个用递归来求斐波那契数列的例子，简化一下是这样的：
//经典递归
function&#160;fibonacci(n) {&#160;
&#160; &#160; return&#160;(function(n) {&#160;
&#160; &#160; &#160; &#160; if&#160;(n == 1 &#124;&#124; n == 2)&#160;
&#160; &#160; &#160; &#160; &#160; &#160; return&#160;1; 
&#160; &#160; &#160; &#160; return&#160;arguments.callee(n - 1) + arguments.callee(n - 2); 
&#160; &#160; })(n); 
}&#160;
&#160;
fibonacci(4); //result: 3
fibonacci(5); //result: 5
fibonacci(10); //result: 55
这种教科书式的写法出镜率很高，在很多文章里都可以看到，但是速度也特别慢，曾经看到过有些人就拿这种例子来说明“递归的效率低”或者“用javascript做函数式编程效率低”，然后给出迭代的写法……
更新：我今天老老实实的读了SICP的第一章之后发现书中对这个问题其实有很严谨的解释，为了防止自己被骂成民科，赶紧修正了一些说法，加了删除线的文字都是有错误的，新增加的文字用粗体。
其实这个方法速度慢并不是函数式编程（FP）的错，首先要把词义弄清楚，真正的数学意义上的“递归”（recursive）包含了“递推”（recurrence）和“回归”（regression）的过程，在程序执行的过程中，“递归”（recursive）指的是一种方法，把大的复杂的问题分解成更小更简单的问题，逐级分解下去，直到问题的规模小到可以直接求解，然后再逐级向上回溯直到解决最初的问题，用程序来实现这种算法的时候至少包含一次以上的递推执行过程，效率当然比不上直接作一次迭代。递归的计算过程（recursive process）包含了两个阶段，先逐级扩展（expansion），构造起一个由被推迟的操作组成的链条（会被解释器保存在堆栈里），然后在收缩（contraction）阶段逐级回溯执行那些操作。随着递归计算步骤的增多，这种方法消耗的资源会越来越大，而且会包含越来越多的冗余操作，上面那个求斐波那契数列的例子（在SICP里被称作“树形递归”）在这方面问题尤其严重，因为它的计算步骤会随着参数而指数性的增长。
引用SICP上的图解：

而在编程里常说的递归其实就是简单的指“自己调用自己”的过程，指的是一种语法形式，而不是计算过程，在SICP里使用“递归过程”（recursive procedure）这个词来称呼，表示“一个过程的定义中引用了该过程本身”，在FP里就是一个函数把状态作为参数反复调用自己，来实现迭代的效果，所以未必需要递推一次以上。，用递归过程也可以产生出迭代计算过程（iterative process，迭代计算过程中消耗的资源是一个常量），递归==迭代，这个表达式不仅在lisp,Erlang这类FP语言里成立，在javascript里也一样。
比如那个求斐波那契数列的例子就可以用尾递归：
//尾递归
function&#160;fibonacci(n) {&#160;
&#160; &#160; return&#160;(function(n1, n2, i) {&#160;
&#160; &#160; &#160; [...]]]></description>
			<content:encoded><![CDATA[<p>刚才在IBM DW上看到这篇<a target="_blank" href="http://www.ibm.com/developerworks/cn/web/wa-lo-dojoajax1/?ca=drs-tp4408">《JavaScript 技巧与高级特性》</a>，其中关于arguments.callee的部分有一个用递归来求斐波那契数列的例子，简化一下是这样的：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: #ffa500;">//经典递归</span></li>
<li><span style="color: Green;">function</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">fibonacci</span><span style="color: Olive;">(</span><span style="color: Blue;">n</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Olive;">{</span><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">n</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Olive;">{</span><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">if</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">(</span><span style="color: Blue;">n</span><span style="color: Gray;"> == </span><span style="color: Maroon;">1</span><span style="color: Gray;"> || </span><span style="color: Blue;">n</span><span style="color: Gray;"> == </span><span style="color: Maroon;">2</span><span style="color: Olive;">)</span><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Maroon;">1</span><span style="color: Gray;">; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">arguments</span><span style="color: Gray;">.</span><span style="color: Blue;">callee</span><span style="color: Olive;">(</span><span style="color: Blue;">n</span><span style="color: Gray;"> - </span><span style="color: Maroon;">1</span><span style="color: Olive;">)</span><span style="color: Gray;"> + </span><span style="color: Blue;">arguments</span><span style="color: Gray;">.</span><span style="color: Blue;">callee</span><span style="color: Olive;">(</span><span style="color: Blue;">n</span><span style="color: Gray;"> - </span><span style="color: Maroon;">2</span><span style="color: Olive;">)</span><span style="color: Gray;">; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">})(</span><span style="color: Blue;">n</span><span style="color: Olive;">)</span><span style="color: Gray;">; </span></li>
<li><span style="color: Olive;">}</span><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Blue;">fibonacci</span><span style="color: Olive;">(</span><span style="color: Maroon;">4</span><span style="color: Olive;">)</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//result: 3</span></li>
<li><span style="color: Blue;">fibonacci</span><span style="color: Olive;">(</span><span style="color: Maroon;">5</span><span style="color: Olive;">)</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//result: 5</span></li>
<li><span style="color: Blue;">fibonacci</span><span style="color: Olive;">(</span><span style="color: Maroon;">10</span><span style="color: Olive;">)</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//result: 55</span></li></ol></div>
<p>这种教科书式的写法出镜率很高，在很多文章里都可以看到，但是速度也特别慢，曾经看到过有些人就拿这种例子来说明“递归的效率低”或者“用javascript做函数式编程效率低”，然后给出迭代的写法……</p>
<p><strong style="color:#ff0000">更新：我今天老老实实的读了<a href="http://www.douban.com/subject/1148282/" target="_blank">SICP</a>的第一章之后发现书中对这个问题其实有很严谨的解释，为了防止自己被骂成民科，赶紧修正了一些说法，加了删除线的文字都是有错误的，新增加的文字用粗体。</strong><span id="more-199"></span></p>
<p>其实这个方法速度慢并不是函数式编程（FP）的错，首先要把词义弄清楚，<del datetime="2008-11-23T13:37:36+00:00">真正的数学意义上的“递归”（recursive）包含了“递推”（recurrence）和“回归”（regression）的过程，</del><span style="color:#990000">在程序执行的过程中，“递归”（recursive）指的是一种方法，</span>把大的复杂的问题分解成更小更简单的问题，逐级分解下去，直到问题的规模小到可以直接求解，然后再逐级向上回溯直到解决最初的问题，<del datetime="2008-11-23T13:37:36+00:00">用程序来实现这种算法的时候至少包含一次以上的递推执行过程，效率当然比不上直接作一次迭代。</del><span style="color:#990000">递归的计算过程（recursive process）包含了两个阶段，先逐级扩展（expansion），构造起一个由被推迟的操作组成的链条（会被解释器保存在堆栈里），然后在收缩（contraction）阶段逐级回溯执行那些操作。随着递归计算步骤的增多，这种方法消耗的资源会越来越大，而且会包含越来越多的冗余操作，上面那个求斐波那契数列的例子（在SICP里被称作“树形递归”）在这方面问题尤其严重，因为它的计算步骤会随着参数而指数性的增长。</span></p>
<p>引用SICP上的图解：<br />
<img src="http://mitpress.mit.edu/sicp/full-text/book/ch1-Z-G-13.gif" alt="scip" /></p>
<p>而在编程里常说的递归其实就是简单的指“自己调用自己”的过程，<span style="color:#990000">指的是一种语法形式，而不是计算过程，在SICP里使用“递归过程”（recursive procedure）这个词来称呼，表示“一个过程的定义中引用了该过程本身”，</span>在FP里就是一个函数把状态作为参数反复调用自己，<del datetime="2008-11-23T13:37:36+00:00">来实现迭代的效果，所以未必需要递推一次以上。</del>，<span style="color:#990000">用递归过程也可以产生出迭代计算过程（iterative process，迭代计算过程中消耗的资源是一个常量），</span>递归==迭代，这个表达式不仅在lisp,Erlang这类FP语言里成立，在javascript里也一样。</p>
<p>比如那个求斐波那契数列的例子就可以用尾递归：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: #ffa500;">//尾递归</span></li>
<li><span style="color: Green;">function</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">fibonacci</span><span style="color: Olive;">(</span><span style="color: Blue;">n</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Olive;">{</span><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">n1</span><span style="color: Gray;">, </span><span style="color: Blue;">n2</span><span style="color: Gray;">, </span><span style="color: Blue;">i</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Olive;">{</span><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">(</span><span style="color: Gray;"> </span><span style="color: Blue;">i</span><span style="color: Gray;"> &lt; </span><span style="color: Blue;">n</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;"> ? </span><span style="color: Blue;">arguments</span><span style="color: Gray;">.</span><span style="color: Blue;">callee</span><span style="color: Olive;">(</span><span style="color: Blue;">n2</span><span style="color: Gray;">, </span><span style="color: Blue;">n1</span><span style="color: Gray;">+</span><span style="color: Blue;">n2</span><span style="color: Gray;">, </span><span style="color: Blue;">i</span><span style="color: Gray;">+</span><span style="color: Maroon;">1</span><span style="color: Olive;">)</span><span style="color: Gray;"> : </span><span style="color: Blue;">n1</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">})(</span><span style="color: Maroon;">1</span><span style="color: Gray;">,</span><span style="color: Maroon;">1</span><span style="color: Gray;">,</span><span style="color: Maroon;">1</span><span style="color: Olive;">)</span><span style="color: Gray;">; </span></li>
<li><span style="color: Olive;">}</span></li></ol></div>
<p>跟这样的迭代方法是完全等价的：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: #ffa500;">//等价的循环</span></li>
<li><span style="color: Green;">function</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">fibonacci</span><span style="color: Olive;">(</span><span style="color: Blue;">n</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Olive;">{</span><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">n1</span><span style="color: Gray;"> = </span><span style="color: Blue;">n2</span><span style="color: Gray;"> = </span><span style="color: Blue;">s</span><span style="color: Gray;"> = </span><span style="color: Blue;">i</span><span style="color: Gray;"> = </span><span style="color: Maroon;">1</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">for</span><span style="color: Olive;">(</span><span style="color: Gray;">; </span><span style="color: Blue;">i</span><span style="color: Gray;">&lt;</span><span style="color: Blue;">n</span><span style="color: Gray;">; </span><span style="color: Blue;">i</span><span style="color: Gray;">++</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">s</span><span style="color: Gray;"> = </span><span style="color: Blue;">n1</span><span style="color: Gray;"> + </span><span style="color: Blue;">n2</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">n1</span><span style="color: Gray;"> = </span><span style="color: Blue;">n2</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">n2</span><span style="color: Gray;"> = </span><span style="color: Blue;">s</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">n1</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">}</span></li></ol></div>
<p>速度测试：</p>
<p><iframe src="http://www.limboy.com/demo/recursion.html" style="width:400px;height:180px;" ></iframe></p>
<p>都是从数列的起始处开始递推，区别只是：在迭代方法里是把每两个相邻的数相加的和保存在循环体外部的局部变量里，在尾递归方法中是把这个和作为参数传给下一次函数调用。</p>
<p>附带说一下，“尾递归”（Tail Recursion）指的是<del datetime="2008-11-23T13:37:36+00:00">把计算过程集中在函数递归调用的最后一次</del><span style="color:#990000">把每次函数递归调用中的所有运算结果或操作都逐步传递到最末尾一次的函数调用，</span>FP语言在编译/解释的时候都会把尾递归优化成一次直接的运算，而在javascript引擎里就算没有优化，至少也可以在每次调用过程中不留下任何痕迹，可以像普通的循环语句那样线性的推算到最后，因此无论速度还是内存消耗，都跟普通的迭代方法没有区别。</p>
<p><a href='http://www.limboy.com/wp-content/uploads/2008/11/ascending_and_descending.jpg' target="_blank"><img src='http://www.limboy.com/wp-content/uploads/2008/11/ascending_and_descending.jpg' style="width:200px;" /></a><br />
<br/><br/><br />
==============正文结束的分割线=================<br />
<br/><br/><br />
吐槽时间到～</p>
<p>关于javascript的尾递归我估计肯定有很多人写过，<a target="_blank" href="http://osteele.com/">Oliver Steele</a>这样的大神就不用说了，中文的应该也有很多，我都懒得去google，所以如果火星了请一定要谅解………</p>
<p>我决定还是要尽量克服这种“火星恐惧症”，因为如果总是担心要写的东西太老土太平常太小白或是已经被人写过，大概就没办法在blog上交流技术了。我最近因为人际关系和情感上的问题比以前更自闭了，没心情写blog，没动力在javaeye发帖子，也没兴趣在IM上跟人说话……前几天跟一个在北京IBM做前端开发的同学说了几句话，好像是几个月来第一次跟陌生人交流……对了顺便说一下，在IM上找我的时候，请务必在第一句话里说明意图，即使在我被外向虚荣亢奋型人格占据的时间段里，对于只说一句“Hi”的聊天窗口，我也是会觉得不知所措并产生抗拒心理的……</p>
<p>最近准备参加两场技术交流活动，一个是29日的<a target="_blank" href="http://www.d2forum.org/d2/3/index.html">D2前端技术论坛</a>，这次因为在魔都举办，所以我们土豆在名义和物质上是主办方，托CTO的关系在徐家汇微软的地盘借了一处场子（由于以前空空荡荡的土豆仓库早就被新员工挤满，还有一大堆门禁，不适合举办活动），但是听说报名人数已经超过500，场子装不下必须做筛选了……</p>
<p>之所以用“听说”这个词是因为我没参与任何组织工作，到时候也不用被推上台讲啥，自闭还是有好处的挖哈哈哈哈～～当初跟<a target="_blank" href="http://www.mikkolee.com/">小麦</a>同学讨论的时候，我建议请国外强者来撑场面，比如南征北战的javascript福音战士，Mozilla的John Resig，可惜没人推动……</p>
<p>另一个活动是12月4日在帝都举办的<a target="_blank" href="http://www.sd2china2008.com/">SD2.0大会</a>，尽管在大萧条的背景下，我仍然义无反顾的在infoQ花1000rmb买了票……结果<a target="_blank" href="http://friendfeed.com/e/129442c7-6cc7-5163-76db-47c26146ceef/555-infoQ-SD2-0-CSDN-YY-P-YY/">被证明投资失误</a>……</p>
<p>如果吐槽的字数超过正文当然会是很囧的事情，所以虽然好久没在blog上写东西，我还是尽快收尾算了：</p>
<p>1，这个blog主要作为发布文章和项目的地方，所以如果我没有谷出自己喜欢的新鲜货，就不会有更新。我平时的更新多数都在twitter和friendfeed上。</p>
<p>2，我把twitter作为日常吐槽的地方，优点是可以约束我少写字，另外，我把twitter当作微博客而不是聊天/短信工具来使用：</p>
<p><a target="_blank" href="http://twitter.com/dexteryy">http://twitter.com/dexteryy</a></p>
<p>3，我的分享主要发布在friendfeed，这是我目前最喜欢最常用依赖程度仅次于google reader的应用，欢迎订阅～</p>
<p><a target="_blank" href="http://friendfeed.com/dexteryy">http://friendfeed.com/dexteryy</a></p>
<p>好了，趁着捣鼓斐波那契数列的热情，我要去看SICP和算法导论了……</p>
]]></content:encoded>
			<wfw:commentRss>http://www.limboy.com/2008/11/22/javascript-tail-recursion/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>新项目&#8221;YyOPML&#8221;——把OPML转换成web界面——大家一起来晒feed订阅列表吧！</title>
		<link>http://www.limboy.com/2008/05/31/yyopml-release/</link>
		<comments>http://www.limboy.com/2008/05/31/yyopml-release/#comments</comments>
		<pubDate>Fri, 30 May 2008 17:28:30 +0000</pubDate>
		<dc:creator>Dexter.Yy</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Web2.0]]></category>
		<category><![CDATA[XML]]></category>
		<category><![CDATA[web服务/应用]]></category>
		<category><![CDATA[界面]]></category>

		<guid isPermaLink="false">http://www.limboy.com/2008/05/31/yyopml-release/</guid>
		<description><![CDATA[首先要说一下目前的矛盾现状：一方面feed订阅和在线阅读器都还不够普及，多数普通网民就算经常访问blog网站，也还没养成订阅的习惯，主要还是通过门户媒体获取资讯，另一个方面，较早开始接触RSS订阅的人——特别是那些blogger和互联网geek们——不但已经对各种在线或离线的阅读器了如指掌，把阅读feed变成了上网的主要活动和习惯，而且很多人收集的feed已经多到让自己烦恼焦虑的程度。后者努力的整理删减自己的订阅列表，前者却经常抱怨不知道怎么寻找可订阅的信息来源…………这种不平衡于是引发了一种禁断的活动——朋友之间交换OPML订阅列表……
OPML是Google Reader乃至所有阅读器都支持导入导出的一种XML规范的“大纲(outline)”数据文件（题头图片里那个蓝色的方块就是OPML的标志，跟feed的著名橙色标志对应，说实话写文前我还不知道OPML也有标志……囧），通常包含用户订阅的所有feed，之所以说是“禁断”……是因为交换这种文件，直接导入到双方的阅读器里之后，很容易使信息爆炸的程度翻倍，而且对于这些导入的feed，不能像原主人那样清楚来历和订阅的理由，于是也不知道该如何看……因此直接交换的下场通常都很惨……
这个项目就是我的解决方案：让导出的OPML源文件支持直接在浏览器里作为网页来展示，而界面上使用完全展开的并排布局，可以像hao123或谷歌网站导航那样一目了然的查找网址，让访问者自己来挑选值得订阅的feed。(不过，你要有使用标签分类feed的习惯，否则显示效果肯定不好…不过那样的话，就算用常规的树状布局，效果也很差的…)
以下是示例页面，这里的“dexteryy.xml”就是我从自己的google reader里导出的OPML文件，包含完整的订阅列表：
http://www.limboy.com/yyopml/dexteryy.xml
还有谁像我一样没什么隐私担心暴露愿意分享OPML的话，可以留下网址或opml文件，我会收集到上面来……
项目主页：http://code.google.com/p/yyopml/
下载程序源码：http://code.google.com/p/yyopml/downloads/list
使用方法是：用文本编辑器打开OPML文件，在第一行后面加上以下内容：
&#60;?xml-stylesheet href=&#34;style/yyopml.xsl&#34; type=&#34;text/xsl&#34;?&#62;
然后跟解压出来的style目录一起传到服务器上，保持在同一个目录里，就可以直接用浏览器看opml文件了。
目前我提供的界面主题有两种，都是如上所说的“网站导航”风格，一个是灰色的面板风格（默认），一个是GOOGLE风格，对应的CSS文件分别是style/ui/yyopml_panel.css和style/ui/yyopml_google.css
支持在页面里切换皮肤，如果要更换默认皮肤，请修改style/ui/yyopml.js里的以下代码：
theme = theme &#124;&#124; &#34;panel&#34;;
把“panel”换成你要改成默认设置的css文件的后缀，比如&#8221;google&#8221;。
也可以在网址里加上参数，直接调用某种皮肤，比如&#8221;http://www.limboy.com/yyopml/dexteryy.xml#theme=google&#8220;，可以用google风格作为默认皮肤打开页面。
==================面向Coder的分界线====================
源码包括一个用来把XML转换成HTML来显示的XSL文件，和界面效果相关的文件。其中yy_core.js是我开发中的一个轻量级/FP风格的javascript库，很多代码都基于jquery，同名的方法接口也尽量跟jquery保持一致，命名空间跟土豆网的js库一样叫“TUI”，提供DOM选择器（我重写的精简功能）和一些常用工具，比jquery小很多(压缩后12k)，这个东西其实年初就想发出来……但是后来懒了，这次考虑到完成度的问题，也懒得在google code里开项目了，源码包里的yy_core.js是一个base64压缩过的版本……
另外，yyopml.js里有一个滚动条插件，是做这个项目的时候心血来潮写的，可以用类似这样的代码：$(&#8220;.list&#8221;).scrollbar(); 给那些外部容器overflow:hidden，内部容器高度超长的元素加上CSS定义的滚动条，支持鼠标滚轮，因为是基于“迷你jquery”来开发，所以应该很容易改成jquery的插件，厌倦了overflow:scroll滚动条的同学可以参考一下。
]]></description>
			<content:encoded><![CDATA[<p><a href='http://www.limboy.com/2008/05/31/yyopml-release/rss-opmljpg-2/' rel='attachment wp-att-194' title='rss-opml.jpg'><img src='http://www.limboy.com/wp-content/uploads/2008/06/rss-opml.jpg' alt='rss-opml.jpg' style="float:left;border:0;margin:0 5px 5px 0;" /></a>首先要说一下目前的矛盾现状：一方面feed订阅和在线阅读器都还不够普及，多数普通网民就算经常访问blog网站，也还没养成订阅的习惯，主要还是通过门户媒体获取资讯，另一个方面，较早开始接触RSS订阅的人——特别是那些blogger和互联网geek们——不但已经对各种在线或离线的阅读器了如指掌，把阅读feed变成了上网的主要活动和习惯，而且很多人收集的feed已经多到让自己烦恼焦虑的程度。后者努力的整理删减自己的订阅列表，前者却经常抱怨不知道怎么寻找可订阅的信息来源…………这种不平衡于是引发了一种禁断的活动——朋友之间交换OPML订阅列表……<span id="more-192"></span></p>
<p>OPML是Google Reader乃至所有阅读器都支持导入导出的一种XML规范的“大纲(outline)”数据文件（题头图片里那个蓝色的方块就是OPML的标志，跟feed的著名橙色标志对应，说实话写文前我还不知道OPML也有标志……囧），通常包含用户订阅的所有feed，之所以说是“禁断”……是因为交换这种文件，直接导入到双方的阅读器里之后，很容易使信息爆炸的程度翻倍，而且对于这些导入的feed，不能像原主人那样清楚来历和订阅的理由，于是也不知道该如何看……因此直接交换的下场通常都很惨……</p>
<p>这个项目就是我的解决方案：让导出的OPML源文件支持直接在浏览器里作为网页来展示，而界面上使用完全展开的并排布局，可以像hao123或谷歌网站导航那样一目了然的查找网址，让访问者自己来挑选值得订阅的feed。(不过，你要有使用标签分类feed的习惯，否则显示效果肯定不好…不过那样的话，就算用常规的树状布局，效果也很差的…)</p>
<p>以下是示例页面，这里的“dexteryy.xml”就是我从自己的google reader里导出的OPML文件，包含完整的订阅列表：</p>
<p><a href="http://www.limboy.com/yyopml/dexteryy.xml" target="_blank">http://www.limboy.com/yyopml/dexteryy.xml</a></p>
<p>还有谁像我一样没什么隐私担心暴露愿意分享OPML的话，可以留下网址或opml文件，我会收集到上面来……</p>
<p>项目主页：<a href="http://code.google.com/p/yyopml/" target="_blank">http://code.google.com/p/yyopml/</a></p>
<p>下载程序源码：<a href="http://code.google.com/p/yyopml/downloads/list" target="_blank" target="_blank">http://code.google.com/p/yyopml/downloads/list</a></p>
<p>使用方法是：用文本编辑器打开OPML文件，在第一行后面加上以下内容：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Olive;">&lt;?</span><span style="color: Green;">xml-stylesheet</span><span style="color: Gray;"> </span><span style="color: #00008b;">href</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">style/yyopml.xsl</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: #00008b;">type</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">text/xsl</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">?&gt;</span></li></ol></div>
<p>然后跟解压出来的style目录一起传到服务器上，保持在同一个目录里，就可以直接用浏览器看opml文件了。</p>
<p>目前我提供的界面主题有两种，都是如上所说的“网站导航”风格，一个是灰色的面板风格（默认），一个是GOOGLE风格，对应的CSS文件分别是style/ui/yyopml_panel.css和style/ui/yyopml_google.css</p>
<p>支持在页面里切换皮肤，如果要更换默认皮肤，请修改style/ui/yyopml.js里的以下代码：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Blue;">theme</span><span style="color: Gray;"> = </span><span style="color: Blue;">theme</span><span style="color: Gray;"> || </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">panel</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">;</span></li></ol></div>
<p>把“panel”换成你要改成默认设置的css文件的后缀，比如&#8221;google&#8221;。</p>
<p>也可以在网址里加上参数，直接调用某种皮肤，比如&#8221;<a href="http://www.limboy.com/yyopml/dexteryy.xml#theme=google" target="_blank">http://www.limboy.com/yyopml/dexteryy.xml#theme=google</a>&#8220;，可以用google风格作为默认皮肤打开页面。</p>
<p>==================面向Coder的分界线====================</p>
<p>源码包括一个用来把XML转换成HTML来显示的XSL文件，和界面效果相关的文件。其中yy_core.js是我开发中的一个轻量级/FP风格的javascript库，很多代码都基于jquery，同名的方法接口也尽量跟jquery保持一致，命名空间跟土豆网的js库一样叫“TUI”，提供DOM选择器（我重写的精简功能）和一些常用工具，比jquery小很多(压缩后12k)，这个东西其实年初就想发出来……但是后来懒了，这次考虑到完成度的问题，也懒得在google code里开项目了，源码包里的yy_core.js是一个base64压缩过的版本……</p>
<p>另外，yyopml.js里有一个滚动条插件，是做这个项目的时候心血来潮写的，可以用类似这样的代码：$(&#8220;.list&#8221;).scrollbar(); 给那些外部容器overflow:hidden，内部容器高度超长的元素加上CSS定义的滚动条，支持鼠标滚轮，因为是基于“迷你jquery”来开发，所以应该很容易改成jquery的插件，厌倦了overflow:scroll滚动条的同学可以参考一下。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.limboy.com/2008/05/31/yyopml-release/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>JavaScript Memoization：让函数也有记忆功能</title>
		<link>http://www.limboy.com/2008/04/27/javascript_memoization/</link>
		<comments>http://www.limboy.com/2008/04/27/javascript_memoization/#comments</comments>
		<pubDate>Sun, 27 Apr 2008 02:57:54 +0000</pubDate>
		<dc:creator>Dexter.Yy</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[代码]]></category>

		<guid isPermaLink="false">http://www.limboy.com/2008/04/27/javascript_memoization/</guid>
		<description><![CDATA[realazy在blog上给出了一个JavaScript Memoization的实现，Memoization就是函数返回值的缓存，比如一个函数参数与返回结果一一对应的hash列表，wiki上其实也有详细解释，我不细说了，只讨论一下具体实现的问题，realazy文中的代码有一些问题，比如直接用参数拼接成的字符串作为查询缓存结果的key，如果参数里包括对象或数组的话，就很难保证唯一的key，还有1楼评论里提到的：[221,3]和[22,13]这样的参数也无法区分。 
那么来改写一下，首先还是用hash表来存放缓存数据：

function Memoize(fn){
&#160; &#160; var&#160;cache = {};
&#160; &#160; return&#160;function(){
&#160; &#160; &#160; &#160; var&#160;key = [];
&#160; &#160; &#160; &#160; for(&#160;var i=0, l = arguments.length; i &#60; l; i++ )&#160;
&#160; &#160; &#160; &#160; &#160; &#160; key.push(arguments[i]);
&#160; &#160; &#160; &#160; if( !(key&#160;in cache) )
&#160; &#160; &#160; &#160; &#160; &#160; cache[key] = fn.apply(this, arguments);
&#160; &#160; &#160; &#160; return&#160;cache[key];
&#160; [...]]]></description>
			<content:encoded><![CDATA[<p><a href='http://www.limboy.com/wp-content/uploads/2008/04/ltp.jpg' title='ltp.jpg'><img src='http://www.limboy.com/wp-content/uploads/2008/04/ltp.jpg' alt='ltp.jpg' style="float:left;margin:0 10px 5px 0;width:200px;" /></a>realazy在blog上给出了一个<a target="_blank" href="http://realazy.org/blog/2008/04/22/javascript-memoization/">JavaScript Memoization的实现</a>，Memoization就是函数返回值的缓存，比如一个函数参数与返回结果一一对应的hash列表，wiki上其实也有<a target="_blank" href="http://en.wikipedia.org/wiki/Memoization">详细解释</a>，我不细说了，只讨论一下具体实现的问题，realazy文中的代码有一些问题，比如直接用参数拼接成的字符串作为查询缓存结果的key，如果参数里包括对象或数组的话，就很难保证唯一的key，还有1楼评论里提到的：[221,3]和[22,13]这样的参数也无法区分。 </p>
<p>那么来改写一下，首先还是用hash表来存放缓存数据：<span id="more-188"></span><br />
<br/><br/></p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Green;">function</span><span style="color: Gray;"> </span><span style="color: Blue;">Memoize</span><span style="color: Olive;">(</span><span style="color: Blue;">fn</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">cache</span><span style="color: Gray;"> = </span><span style="color: Olive;">{}</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">function</span><span style="color: Olive;">(){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">key</span><span style="color: Gray;"> = </span><span style="color: Olive;">[]</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">for</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">var</span><span style="color: Gray;"> </span><span style="color: Blue;">i</span><span style="color: Gray;">=</span><span style="color: Maroon;">0</span><span style="color: Gray;">, </span><span style="color: Blue;">l</span><span style="color: Gray;"> = </span><span style="color: Blue;">arguments</span><span style="color: Gray;">.</span><span style="color: Blue;">length</span><span style="color: Gray;">; </span><span style="color: Blue;">i</span><span style="color: Gray;"> &lt; </span><span style="color: Blue;">l</span><span style="color: Gray;">; </span><span style="color: Blue;">i</span><span style="color: Gray;">++ </span><span style="color: Olive;">)</span><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">key</span><span style="color: Gray;">.</span><span style="color: Blue;">push</span><span style="color: Olive;">(</span><span style="color: Blue;">arguments</span><span style="color: Olive;">[</span><span style="color: Blue;">i</span><span style="color: Olive;">])</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">if</span><span style="color: Olive;">(</span><span style="color: Gray;"> !</span><span style="color: Olive;">(</span><span style="color: Blue;">key</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">in</span><span style="color: Gray;"> </span><span style="color: Blue;">cache</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">cache</span><span style="color: Olive;">[</span><span style="color: Blue;">key</span><span style="color: Olive;">]</span><span style="color: Gray;"> = </span><span style="color: Blue;">fn</span><span style="color: Gray;">.</span><span style="color: Blue;">apply</span><span style="color: Olive;">(</span><span style="color: Green;">this</span><span style="color: Gray;">, </span><span style="color: Blue;">arguments</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">cache</span><span style="color: Olive;">[</span><span style="color: Blue;">key</span><span style="color: Olive;">]</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">}</span></li></ol></div>
<p>嗯，区别是直接把数组当作键来用，不过要注意函数里的arguments是js解释器实现的一个特殊对象，并不是真正的数组，所以要转换一下……</p>
<blockquote><p>
ps: 原来的参数包括方法名称和上下文引用：fib.fib_memo = Memoize(&#8216;fib_memo&#8217;, fib)，但实际上currying生成的函数里可以用this直接引用上层对象，更复杂的例子可以参考<a target="_blank" href="http://ejohn.org/blog/simple-class-instantiation/">John Resig的makeClass</a>，所以我改成直接传函数引用：fib.fib_memo = Memoize(fib.fib_memo)</p></blockquote>
<p>这样写看上去似乎很靠谱，由参数组成的数组不是唯一的么。但实际上，数组之所以能作为js对象的属性名称来使用，是因为它被当作字符串处理了，也就是说如果你给函数传的参数是这样：(1,2,3), cache对象就会是这个样子：{ &#8220;1,2,3&#8243;: somedata }，如果你的参数里有对象，比如：(1,2,{i:&#8221;yy&#8221;})，实际的键值会是：&#8221;1,2,[object Object]&#8220;，所以这跟把数组拼接成字符串的方法其实没有区别……</p>
<p>示例：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Green;">var</span><span style="color: Gray;"> </span><span style="color: Blue;">a</span><span style="color: Gray;"> = </span><span style="color: Olive;">[</span><span style="color: Maroon;">1</span><span style="color: Gray;">,</span><span style="color: Maroon;">2</span><span style="color: Gray;">,</span><span style="color: Olive;">{</span><span style="color: Blue;">yy</span><span style="color: Gray;">:</span><span style="color: #8b0000;">'</span><span style="color: Red;">0</span><span style="color: #8b0000;">'</span><span style="color: Olive;">}]</span><span style="color: Gray;">;</span></li>
<li><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">b</span><span style="color: Gray;"> = </span><span style="color: Olive;">[</span><span style="color: Maroon;">1</span><span style="color: Gray;">,</span><span style="color: Maroon;">2</span><span style="color: Gray;">,</span><span style="color: Olive;">{</span><span style="color: Blue;">xx</span><span style="color: Gray;">:</span><span style="color: #8b0000;">'</span><span style="color: Red;">1</span><span style="color: #8b0000;">'</span><span style="color: Olive;">}]</span><span style="color: Gray;">;</span></li>
<li><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">obj</span><span style="color: Gray;"> = </span><span style="color: Olive;">{}</span><span style="color: Gray;">;</span></li>
<li><span style="color: Blue;">obj</span><span style="color: Olive;">[</span><span style="color: Blue;">a</span><span style="color: Olive;">]</span><span style="color: Gray;"> = </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">111</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">;</span></li>
<li><span style="color: Blue;">obj</span><span style="color: Olive;">[</span><span style="color: Blue;">b</span><span style="color: Olive;">]</span><span style="color: Gray;"> = </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">222</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">;</span></li>
<li><span style="color: Green;">for</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">var</span><span style="color: Gray;"> </span><span style="color: Blue;">i</span><span style="color: Gray;"> </span><span style="color: Green;">in</span><span style="color: Gray;"> </span><span style="color: Blue;">obj</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">alert</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">i</span><span style="color: Gray;"> + </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;"> = </span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> + </span><span style="color: Blue;">obj</span><span style="color: Olive;">[</span><span style="color: Blue;">i</span><span style="color: Olive;">]</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;">;&nbsp; &nbsp; </span><span style="color: #ffa500;">//只会弹出&quot;1,2,[object Object] = 222&quot;，obj[a] = &quot;111&quot;被覆盖了</span></li></ol></div>
<p>直接用参数作为键名的方法不靠谱了…………换一种方法试试：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Green;">function</span><span style="color: Gray;"> </span><span style="color: Blue;">Memoize</span><span style="color: Olive;">(</span><span style="color: Blue;">fn</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">cache</span><span style="color: Gray;"> = </span><span style="color: Olive;">{}</span><span style="color: Gray;">, </span><span style="color: Blue;">args</span><span style="color: Gray;"> = </span><span style="color: Olive;">[]</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">function</span><span style="color: Olive;">(){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">for</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">var</span><span style="color: Gray;"> </span><span style="color: Blue;">i</span><span style="color: Gray;">=</span><span style="color: Maroon;">0</span><span style="color: Gray;">, </span><span style="color: Blue;">key</span><span style="color: Gray;"> = </span><span style="color: Blue;">args</span><span style="color: Gray;">.</span><span style="color: Blue;">length</span><span style="color: Gray;">; </span><span style="color: Blue;">i</span><span style="color: Gray;"> &lt; </span><span style="color: Blue;">key</span><span style="color: Gray;">; </span><span style="color: Blue;">i</span><span style="color: Gray;">++ </span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">if</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">equal</span><span style="color: Olive;">(</span><span style="color: Gray;"> </span><span style="color: Blue;">args</span><span style="color: Olive;">[</span><span style="color: Blue;">i</span><span style="color: Olive;">]</span><span style="color: Gray;">, </span><span style="color: Blue;">arguments</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;">&nbsp; </span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">cache</span><span style="color: Olive;">[</span><span style="color: Blue;">i</span><span style="color: Olive;">]</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">}</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">args</span><span style="color: Olive;">[</span><span style="color: Blue;">key</span><span style="color: Olive;">]</span><span style="color: Gray;"> = </span><span style="color: Blue;">arguments</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">cache</span><span style="color: Olive;">[</span><span style="color: Blue;">key</span><span style="color: Olive;">]</span><span style="color: Gray;"> = </span><span style="color: Blue;">fn</span><span style="color: Gray;">.</span><span style="color: Blue;">apply</span><span style="color: Olive;">(</span><span style="color: Green;">this</span><span style="color: Gray;">, </span><span style="color: Blue;">arguments</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">cache</span><span style="color: Olive;">[</span><span style="color: Blue;">key</span><span style="color: Olive;">]</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">}</span></li></ol></div>
<p>可以完全避免上述问题，没有使用hash的键值对索引，而是把函数的参数和结果分别缓存在两个列表里，每次都先遍历整个参数列表作比较，找出对应的键名/ID号之后再从结果列表里取数据。以下是比较数组的equal方法：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Green;">function</span><span style="color: Gray;"> </span><span style="color: Blue;">equal</span><span style="color: Olive;">(</span><span style="color: Gray;"> </span><span style="color: Blue;">first</span><span style="color: Gray;">, </span><span style="color: Blue;">second</span><span style="color: Gray;"> </span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">if</span><span style="color: Olive;">(</span><span style="color: Gray;"> !</span><span style="color: Blue;">first</span><span style="color: Gray;"> || !</span><span style="color: Blue;">second</span><span style="color: Gray;"> || </span><span style="color: Blue;">first</span><span style="color: Gray;">.</span><span style="color: Blue;">constructor</span><span style="color: Gray;"> != </span><span style="color: Blue;">second</span><span style="color: Gray;">.</span><span style="color: Blue;">constructor</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">false</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">if</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">first</span><span style="color: Gray;">.</span><span style="color: Blue;">length</span><span style="color: Gray;"> &amp;&amp; </span><span style="color: Green;">typeof</span><span style="color: Gray;"> </span><span style="color: Blue;">first</span><span style="color: Gray;"> != </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">string</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">&nbsp; </span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">for</span><span style="color: Olive;">(</span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">i</span><span style="color: Gray;">=</span><span style="color: Maroon;">0</span><span style="color: Gray;">, </span><span style="color: Blue;">l</span><span style="color: Gray;"> = </span><span style="color: Olive;">(</span><span style="color: Gray;"> </span><span style="color: Blue;">first</span><span style="color: Gray;">.</span><span style="color: Blue;">length</span><span style="color: Gray;"> &gt; </span><span style="color: Blue;">second</span><span style="color: Gray;">.</span><span style="color: Blue;">length</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;"> ? </span><span style="color: Blue;">first</span><span style="color: Gray;">.</span><span style="color: Blue;">length</span><span style="color: Gray;"> : </span><span style="color: Blue;">second</span><span style="color: Gray;">.</span><span style="color: Blue;">length</span><span style="color: Gray;">; </span><span style="color: Blue;">i</span><span style="color: Gray;">&lt;</span><span style="color: Blue;">l</span><span style="color: Gray;">; </span><span style="color: Blue;">i</span><span style="color: Gray;">++</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">if</span><span style="color: Olive;">(</span><span style="color: Gray;"> !</span><span style="color: Blue;">equal</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">first</span><span style="color: Olive;">[</span><span style="color: Blue;">i</span><span style="color: Olive;">]</span><span style="color: Gray;">, </span><span style="color: Blue;">second</span><span style="color: Olive;">[</span><span style="color: Blue;">i</span><span style="color: Olive;">]</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Green;">return</span><span style="color: Gray;"> </span><span style="color: Green;">false</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">}</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">else</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">if</span><span style="color: Olive;">(</span><span style="color: Gray;"> </span><span style="color: Green;">typeof</span><span style="color: Gray;"> </span><span style="color: Blue;">first</span><span style="color: Gray;"> == </span><span style="color: #8b0000;">'</span><span style="color: Red;">object</span><span style="color: #8b0000;">'</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">for</span><span style="color: Olive;">(</span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">n</span><span style="color: Gray;"> </span><span style="color: Green;">in</span><span style="color: Gray;"> </span><span style="color: Blue;">first</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">if</span><span style="color: Olive;">(</span><span style="color: Gray;"> !</span><span style="color: Blue;">equal</span><span style="color: Olive;">(</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">first</span><span style="color: Olive;">[</span><span style="color: Blue;">n</span><span style="color: Olive;">]</span><span style="color: Gray;">, </span><span style="color: Blue;">second</span><span style="color: Olive;">[</span><span style="color: Blue;">n</span><span style="color: Olive;">]</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Green;">return</span><span style="color: Gray;"> </span><span style="color: Green;">false</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">}</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">else</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">(</span><span style="color: Gray;"> </span><span style="color: Blue;">first</span><span style="color: Gray;"> === </span><span style="color: Blue;">second</span><span style="color: Gray;"> </span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">true</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">}</span></li></ol></div>
<p>千万不要直接用==来比较arguments和args里的数组，那样比较的是内存引用，而不是参数的内容。</p>
<p>这种方法的速度很慢，equal方法其实影响不大，但是缓存的结果数量多了以后，每次都要遍历参数列表却是很没效率的（求80以上的fibonacci数列，在firefox3和safari3上都要40ms左右）</p>
<p>如果在实际应用中参数变动不多或者不接受参数的话，可以参考Oliver Steel的这篇<a target="_blank" href="http://osteele.com/archives/2006/04/javascript-memoization">《One-Line JavaScript Memoization》</a>，用很短的函数式风格解决问题：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Green;">function</span><span style="color: Gray;"> </span><span style="color: Blue;">Memoize</span><span style="color: Olive;">(</span><span style="color: Blue;">o</span><span style="color: Gray;">, </span><span style="color: Blue;">p</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">f</span><span style="color: Gray;"> = </span><span style="color: Blue;">o</span><span style="color: Olive;">[</span><span style="color: Blue;">p</span><span style="color: Olive;">]</span><span style="color: Gray;">, </span><span style="color: Blue;">mf</span><span style="color: Gray;">, </span><span style="color: Blue;">value</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">s</span><span style="color: Gray;"> = </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">v</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Olive;">{</span><span style="color: Green;">return</span><span style="color: Gray;"> </span><span style="color: Blue;">o</span><span style="color: Olive;">[</span><span style="color: Blue;">p</span><span style="color: Olive;">]</span><span style="color: Gray;">=</span><span style="color: Blue;">v</span><span style="color: Gray;">||</span><span style="color: Blue;">mf</span><span style="color: Olive;">}</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">((</span><span style="color: Blue;">mf</span><span style="color: Gray;"> = </span><span style="color: Green;">function</span><span style="color: Olive;">()</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">(</span><span style="color: Blue;">s</span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">(){</span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">value</span><span style="color: Olive;">}))</span><span style="color: Gray;">.</span><span style="color: Blue;">reset</span><span style="color: Gray;"> = </span><span style="color: Blue;">mf</span><span style="color: Gray;">.</span><span style="color: Blue;">reset</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">value</span><span style="color: Gray;"> = </span><span style="color: Blue;">f</span><span style="color: Gray;">.</span><span style="color: Blue;">apply</span><span style="color: Olive;">(</span><span style="color: Green;">this</span><span style="color: Gray;">,</span><span style="color: Blue;">arguments</span><span style="color: Olive;">)</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//此处修改过，允许接受参数</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">})</span><span style="color: Gray;">.</span><span style="color: Blue;">reset</span><span style="color: Gray;"> = </span><span style="color: Blue;">s</span><span style="color: Olive;">)()</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">}</span></li></ol></div>
<p>示例：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Green;">var</span><span style="color: Gray;"> </span><span style="color: Blue;">fib</span><span style="color: Gray;"> = </span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Blue;">temp</span><span style="color: Gray;">: </span><span style="color: Green;">function</span><span style="color: Olive;">(</span><span style="color: Blue;">n</span><span style="color: Olive;">){</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">for</span><span style="color: Olive;">(</span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">i</span><span style="color: Gray;">=</span><span style="color: Maroon;">0</span><span style="color: Gray;">;</span><span style="color: Blue;">i</span><span style="color: Gray;">&lt;</span><span style="color: Maroon;">10000</span><span style="color: Gray;">;</span><span style="color: Blue;">i</span><span style="color: Gray;">++</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">n</span><span style="color: Gray;">=</span><span style="color: Blue;">n</span><span style="color: Gray;">+</span><span style="color: Maroon;">2</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">return</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">n</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">}</span></li>
<li><span style="color: Olive;">}</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Blue;">Memoize</span><span style="color: Olive;">(</span><span style="color: Blue;">fib</span><span style="color: Gray;">,</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">temp</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//让fib.temp缓存返回值</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Blue;">fib</span><span style="color: Gray;">.</span><span style="color: Blue;">temp</span><span style="color: Olive;">(</span><span style="color: Maroon;">16</span><span style="color: Olive;">)</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//执行结果：20006，被缓存</span></li>
<li><span style="color: Blue;">fib</span><span style="color: Gray;">.</span><span style="color: Blue;">temp</span><span style="color: Olive;">(</span><span style="color: Maroon;">20</span><span style="color: Olive;">)</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//执行结果：20006</span></li>
<li><span style="color: Blue;">fib</span><span style="color: Gray;">.</span><span style="color: Blue;">temp</span><span style="color: Olive;">(</span><span style="color: Maroon;">10</span><span style="color: Olive;">)</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//执行结果：20006</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Blue;">fib</span><span style="color: Gray;">.</span><span style="color: Blue;">temp</span><span style="color: Gray;">.</span><span style="color: Blue;">reset</span><span style="color: Olive;">()</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//重置缓存</span></li>
<li><span style="color: Blue;">fib</span><span style="color: Gray;">.</span><span style="color: Blue;">temp</span><span style="color: Olive;">(</span><span style="color: Maroon;">10</span><span style="color: Olive;">)</span><span style="color: Gray;">; </span><span style="color: #ffa500;">//执行结果：20010</span></li></ol></div>
]]></content:encoded>
			<wfw:commentRss>http://www.limboy.com/2008/04/27/javascript_memoization/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>iPhone App开发笔记</title>
		<link>http://www.limboy.com/2008/03/08/iphone-app-develop/</link>
		<comments>http://www.limboy.com/2008/03/08/iphone-app-develop/#comments</comments>
		<pubDate>Fri, 07 Mar 2008 19:04:13 +0000</pubDate>
		<dc:creator>Dexter.Yy</dc:creator>
				<category><![CDATA[Apple]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[web服务/应用]]></category>
		<category><![CDATA[界面]]></category>

		<guid isPermaLink="false">http://www.limboy.com/2008/03/08/iphone-app-develop/</guid>
		<description><![CDATA[第一，标题里的app指的是根正苗红老实本分的Web App，昨天的这个时候，对是在昨天，iPhone Web App就等同于iPhone App，咳咳，虽然现在不是了，但我这笔记是两个星期前的……
第二，不全，主要是我关心的一些细节，以及我自己理解的一些东西……


&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;懒得想小标题的分界线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;

html里可以调用系统接口，比如电话拨号：
&#60;a href=&#34;tel:1-408-555-5555&#34;&#62;1-408-555-5555&#60;/a&#62;
还有mail和google map的接口……

&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;懒得想小标题的分界线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;

在js里嗅探iphone的safari环境，要注意agent字符串里有额外两处：
&#8220;Mobile/1A543&#8243;，这个是iphone OS的操作系统版本（注意不是固件版本）
&#8220;iPhone&#8221;，这个是移动平台的类型，如果是ipod touch的话这里会是“ipod”
此外：
&#8220;version/3.0&#8243;，Safari的市场版本号
&#8220;Safari/419.3&#8243;，这个是build版本，虽然iphone跟osx一样都是safari3.0，但build版本号不同
完整的例子：
Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like
Gecko) Version/3.0 Mobile/1A543 Safari/419.3

&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;懒得想小标题的分界线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;

调用css的时候，media类型支持CSS3，比如可以用“only”来屏蔽旧浏览器，用“(min-device-width: 481px)”屏蔽小屏幕手机。由于iphone里的safari不支持print和handheld的media类型，可以用它们来对iphone屏蔽一些css文件。
示例：
&#60;link media=&#34;only screen and (min-device-width: 481px)&#34; href=&#34;not-small-device.css&#34; type=&#34;text/css&#34; rel=&#34;stylesheet&#34; &#62;
也可以作为css选择器里，比如
@media screen {&#160;
#text&#160;{ color: white; background-color: black; }&#160;
}
由于safari支持css3，你还可以享受到的福利包括在background里放6张图片做圆角，给文本加阴影，使用属性选择器之类……

&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;懒得想小标题的分界线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;

iphone的浏览器里有一个很重要的概念是viewport（视区），系统默认的viewport为980像素，可以用meta标签指定，宽度范围从200到10,000，高度范围从223到10,000，还可以使用user-scalable禁止用户缩放页面（常见的iphone web应用，比如facebook,google reader，因为要仿原生界面，都是这样设置的），minimum-scale和maximum-scale可以设置缩放的限制，initial-scale是默认的缩放程度，范围从>0到10
示例：
&#60;meta name=&#34;viewport&#34; content=&#34;width = 320&#34; /&#62;
&#60;meta&#160;name=&#34;viewport&#34; content=&#34;initial-scale=2.3, user-scalable=no&#34; /&#62;
iphone默认的浏览器窗口尺寸是:  竖向（body[orient="profile"]）为宽320px，高356px，横向（body[orient="landscape"]）为宽208px，高480px，但实际上这是显示了浏览器地址栏之后剩余的空间，往下拖动页面时，地址栏会隐藏，所以实际的viewport（竖向）是宽320px，高416px。
页面加载之后可以用 window.scrollTo(0, 1) 隐藏地址栏，自动使用最大化的viewport。
关于viewport，还有一个很重要的概念是：iphone的safari浏览器完全没有滚动条，而且不是简单的“隐藏滚动条”，是根本没有这个功能。所以不但iframe, [...]]]></description>
			<content:encoded><![CDATA[<p><a href='http://www.limboy.com/2008/03/08/iphone-app-develop/index_steps_2jpg/' rel='attachment wp-att-184' title='index_steps_2.jpg'><img src='http://www.limboy.com/wp-content/uploads/2008/03/index_steps_2.jpg' alt='index_steps_2.jpg' style="width:200px;float:left;margin:0 5px 0 0;border:0;" /></a>第一，标题里的app指的是根正苗红老实本分的<a href="http://www.apple.com/webapps/" target="_blank">Web App</a>，昨天的这个时候，对是在昨天，iPhone Web App就等同于iPhone App，咳咳，虽然现在不是了，但我这笔记是两个星期前的……</p>
<p>第二，不全，主要是我关心的一些细节，以及我自己理解的一些东西……<span id="more-182"></span><br />
<br/><br />
<br/><br />
<em style="color:#999;">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;懒得想小标题的分界线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</em><br />
<br/></p>
<p>html里可以调用系统接口，比如电话拨号：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Olive;">&lt;</span><span style="color: Green;">a</span><span style="color: Gray;"> </span><span style="color: #00008b;">href</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">tel:1-408-555-5555</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">&gt;</span><span style="color: Gray;">1-408-555-5555</span><span style="color: Olive;">&lt;/</span><span style="color: Green;">a</span><span style="color: Olive;">&gt;</span></li></ol></div>
<p>还有mail和google map的接口……</p>
<p><br/><br />
<em style="color:#999;">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;懒得想小标题的分界线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</em><br />
<br/></p>
<p>在js里嗅探iphone的safari环境，要注意agent字符串里有额外两处：</p>
<p>&#8220;Mobile/1A543&#8243;，这个是iphone OS的操作系统版本（注意不是固件版本）<br />
&#8220;iPhone&#8221;，这个是移动平台的类型，如果是ipod touch的话这里会是“ipod”</p>
<p>此外：</p>
<p>&#8220;version/3.0&#8243;，Safari的市场版本号<br />
&#8220;Safari/419.3&#8243;，这个是build版本，虽然iphone跟osx一样都是safari3.0，但build版本号不同</p>
<p>完整的例子：</p>
<blockquote><p>Mozilla/5.0 (iPhone; U; CPU like Mac OS X; en) AppleWebKit/420+ (KHTML, like<br />
Gecko) Version/3.0 Mobile/1A543 Safari/419.3</p></blockquote>
<p><br/><br />
<em style="color:#999;">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;懒得想小标题的分界线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</em><br />
<br/></p>
<p>调用css的时候，media类型支持CSS3，比如可以用“only”来屏蔽旧浏览器，用“(min-device-width: 481px)”屏蔽小屏幕手机。由于iphone里的safari不支持print和handheld的media类型，可以用它们来对iphone屏蔽一些css文件。<br />
示例：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Olive;">&lt;</span><span style="color: Green;">link</span><span style="color: Gray;"> </span><span style="color: #00008b;">media</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">only screen and (min-device-width: 481px)</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: #00008b;">href</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">not-small-device.css</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: #00008b;">type</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">text/css</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: #00008b;">rel</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">stylesheet</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: Olive;">&gt;</span></li></ol></div>
<p>也可以作为css选择器里，比如</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: #00008b;">@media</span><span style="color: Gray;"> </span><span style="color: Blue;">screen</span><span style="color: Gray;"> </span><span style="color: Olive;">{</span><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Blue;">#text</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">{</span><span style="color: Gray;"> </span><span style="color: Green;">color:</span><span style="color: Gray;"> </span><span style="color: #00008b;">white</span><span style="color: Gray;">; </span><span style="color: Green;">background-color:</span><span style="color: Gray;"> </span><span style="color: #00008b;">black</span><span style="color: Gray;">; </span><span style="color: Olive;">}</span><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Olive;">}</span></li></ol></div>
<p>由于safari支持css3，你还可以享受到的福利包括在background里放6张图片做圆角，给文本加阴影，使用属性选择器之类……</p>
<p><br/><br />
<em style="color:#999;">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;懒得想小标题的分界线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</em><br />
<br/></p>
<p>iphone的浏览器里有一个很重要的概念是viewport（视区），系统默认的viewport为980像素，可以用meta标签指定，宽度范围从200到10,000，高度范围从223到10,000，还可以使用user-scalable禁止用户缩放页面（常见的iphone web应用，比如facebook,google reader，因为要仿原生界面，都是这样设置的），minimum-scale和maximum-scale可以设置缩放的限制，initial-scale是默认的缩放程度，范围从>0到10<br />
示例：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Olive;">&lt;</span><span style="color: Green;">meta</span><span style="color: Gray;"> </span><span style="color: #00008b;">name</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">viewport</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: #00008b;">content</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">width = 320</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: Olive;">/&gt;</span></li>
<li><span style="color: Olive;">&lt;</span><span style="color: Green;">meta</span><span style="color: Gray;">&nbsp;</span><span style="color: #00008b;">name</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">viewport</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: #00008b;">content</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">initial-scale=2.3, user-scalable=no</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: Olive;">/&gt;</span></li></ol></div>
<p>iphone默认的浏览器窗口尺寸是:  竖向（body[orient="profile"]）为宽320px，高356px，横向（body[orient="landscape"]）为宽208px，高480px，但实际上这是显示了浏览器地址栏之后剩余的空间，往下拖动页面时，地址栏会隐藏，所以实际的viewport（竖向）是宽320px，高416px。<br />
页面加载之后可以用 window.scrollTo(0, 1) 隐藏地址栏，自动使用最大化的viewport。</p>
<p>关于viewport，还有一个很重要的概念是：iphone的safari浏览器完全没有滚动条，而且不是简单的“隐藏滚动条”，是根本没有这个功能。所以不但iframe, overflow:scroll的元素没有滚动条，整个窗口也没有的，iphone的safari浏览器实际上从一开始就完整显示了这个网页，然后用viewport查看其中的一部分。当你用手指拖动时，其实拖的不是页面，而是viewport…………由此引申出的结果很多，比如CSS里的 position:fixed 无效……</p>
<p><br/><br />
<em style="color:#999;">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;懒得想小标题的分界线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</em><br />
<br/></p>
<p>浏览器行为的改变不止是滚动条，交互事件也跟普通桌面不一样：</p>
<p>所有hover动作，还有mouseover，都不存在，链接上的title内容，会在你点击链接并按住不动时弹跳出来（如果你不放开手指，继续移动的话，点击事件不会发生，具体原因下面解释）…………而mouseover，直接转换成了mousedown……</p>
<p>点击页面元素之后发生的事情很复杂…………比如当你用单指按住可点击元素（大约就是默认为block的元素），然后放开，首先触发的event居然是mousemove！ 接下来如果元素内容不变（这个条件比较难理解，我知道），会陆续触发mousedown，mouseup，click，如果内容改变，就不会再触发任何事件……</p>
<p>如果你恰好不太走运的给网页上一些inline元素绑过js事件（这比较常见，我也知道），比如span，有一个不用修改标签的方法是给它们都加上onclick=&#8221;void(0)&#8221;，这样iphone就会认为它们是可点击的元素-_____-b</p>
<p>如果按住元素之后移动手指，当然就不要指望会触发mousemove了，啥事情都没有，不过停下的时候，会触发onscroll （因为你刚才移动了viewport嘛……）</p>
<p>如果你用两个手指做缩放的动作，啥事件都不会有啦，但是如果你用两个手指在屏幕上一起移动，而且所在的位置是一个本来有滚动条的页面元素(比如iframe罢)，会触发一个叫mousewheel的事件（但是别指望iframe本身的内容会滚动-___-b）, 停止移动时同样触发onscroll。</p>
<p>OK，你希望像平时那样用onmousedown,onmouseup,onmousemove来做页面元素的拖拽交互把iphone web app的界面做的像原生界面一样活蹦乱跳的梦想已经破灭了，请努力克制骂乔布斯的欲望。</p>
<p>对了，不用我说也应该想得到，onkeyup，e.charCode，e.keyCode这类玩意都不能用罢？</p>
<p><br/><br />
<em style="color:#999;">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;懒得想小标题的分界线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</em><br />
<br/></p>
<p>默认的html控件的样式大家都已经知道很cool了，不过也可以自己修改，具体内容请查看《iphone用户界面指南》的第三章：<a href="http://developer.apple.com/documentation/iPhone/Conceptual/iPhoneHIG/MetricsLayout/chapter_5_section_1.html#//apple_ref/doc/uid/TP40006596-CH6-SW1" target="_blank">Metrics, Layout Guidelines, and Tips</a></p>
<p>iphone里的safari调整了默认的文字样式，这些调整被包括在了一个新的css属性“-webkit-text-size-adjust”里面，相当于“-webkit-text-size-adjust:auto;”，你可以覆盖它，根据需要改成none或者200%</p>
<p><br/><br />
<em style="color:#999;">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;懒得想小标题的分界线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</em><br />
<br/></p>
<p>web app可以像原生应用一样，在home界面里上添加一个快捷方式图标，方法是增加一个link标签：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Olive;">&lt;</span><span style="color: Green;">link</span><span style="color: Gray;"> </span><span style="color: #00008b;">rel</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">apple-touch-icon</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: #00008b;">href</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">custom_icon.png</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: Olive;">/&gt;</span></li></ol></div>
<p>这是针对单个页面的，如果你把图片命名为“apple-touch-icon.png”，放在网站的某个目录里面，该目录下所有页面都会获得添加图标的功能……</p>
<p>图标的要求是尺寸57×57，png格式，不用画蛇添足的去做圆角渐变或玻璃反光效果，iphone系统会把图片自动裁剪和渲染成统一的风格……</p>
<p>喔对了……不要高兴太早……这个快捷图标的功能，只有1.1.3或更高的固件版本才支持……考虑到国内那些买旧版本破解机器还被商家反复叮嘱不要升级的用户……呃……</p>
<p><br/><br />
<em style="color:#999;">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;懒得想小标题的分界线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</em><br />
<br/></p>
<p>关于网页中的媒体文件，普通图片最大支持200万像素（jpg的话，最大可以显示出3200万的，不过超过200万的jpg都会被压成缩略图），支持的最大尺寸是2 * 1024&#215;1024，gif动画最大支持2m（否则只显示第1帧）</p>
<p>iphone支持的视频格式：</p>
<blockquote><p>H.264 Baseline Profile Level 3.0 video, up to 640 x 480 at 30 fps. Note that B frames are not supported in the Baseline profile.<br />
MPEG-4 Part 2 video (Simple Profile)<br />
AAC-LC audio, up to 48 kHz<br />
.mov, .mp4, .m4v, .3gp file formats</p></blockquote>
<p>需要注意的是这里的“Baseline profile”，由于这种编码的质量跟“Extended Profile”和“main profile”相比效果比较差，目前主流的支持“高清”（h264）的视频网站，比如youtube，土豆，都没有采用Baseline profile压缩h264视频，所以iphone不但不能播放网络上流行的flv视频（因为不支持flash），连刚开始流行的h264也不能直接播放…………提供iphone应用的视频网站无法使用现有资源，不得不压缩iphone专用的视频文件，所以不要指望能立即在iphone上观看视频网站上的所有资源……T__T</p>
<p>由于iphone不支持flash播放器，视频文件只能直接嵌在页面里，用自带的quicktime来全屏播放，示例：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Olive;">&lt;</span><span style="color: Green;">embed</span><span style="color: Gray;"> </span><span style="color: #00008b;">src</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">screen.jpg</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: #00008b;">href</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">movie.m4v</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: #00008b;">type</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">video/x-m4v</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: #00008b;">target</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">myself</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: #00008b;">scale</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">1</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> ...</span><span style="color: Olive;">&gt;</span></li></ol></div>
<p>更多细节请看官方文档：<a href="http://www.apple.com/quicktime/tutorials/embed.html" target="_blank">Including QuickTime In A Web Page</a></p>
<p><br/><br />
<em style="color:#999;">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;懒得想小标题的分界线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</em><br />
<br/></p>
<p>如果想全面了解iphone上的web开发，推荐阅读：</p>
<p><a href="http://developer.apple.com/documentation/iPhone/Conceptual/iPhoneHIG/" target="_blank">iPhone Human Interface Guidelines</a>(官方还有一份名字类似的文档，简称OSXHIG，是<a href="http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/" target="_blank">界面设计者的圣经</a>之一)</p>
<p><a href="http://developer.apple.com/documentation/AppleApplications/Reference/SafariWebContent/" target="_blank">Safari Web Content Guide for iPhone</a> </p>
<p><a href="http://developer.apple.com/internet/webcontent/bestwebdev.html" target="_blank">Web Page Development: Best Practices</a>(这篇可以凑合看看，2月8号刚更新过的)</p>
<p>此外，ADC on iTunes里有好多iphone相关的视频，讨厌翻文档的可以去弄来看看，这可是iTunes store里少有的免费资源喔……</p>
<p><br/><br />
<em style="color:#999;">&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;懒得想小标题的分界线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;</em><br />
<br/></p>
<p>就像开头说的，这是2周前写的，一直懒得修改整齐了往blog上帖，但是昨天半夜（好罢是今天凌晨）在<a href="http://twitter.com/apple4us" target="_blank">twitter</a>上不小心看了iphone SDK发布的实况转播……我发现再拖延的话就只能贴到火星去了……</p>
<p>跟华丽的SDK相比，iphone safari上的开发环境可以说很糟糕，非常限制想象力——对javascript和RIA开发者来说，不过只要看看iphone用户上网的热情和相关数据，可以预见在很长一段时间里，iphone平台仍然会是立志开发web app的勇者们争夺的滩头阵地。</p>
<p>啊啊啊啊啊，2.10G的iphone_sdk.dmg终于下载完了，睡觉去……下周买<a href="http://www.china-pub.com/computers/common/info.asp?id=38686">《Cocoa入门&#8211;使用Objective-C》</a>……<br />
<br/><br />
<br/></p>
]]></content:encoded>
			<wfw:commentRss>http://www.limboy.com/2008/03/08/iphone-app-develop/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>在Leopard里配置rails+php+apache+mysql</title>
		<link>http://www.limboy.com/2007/11/14/rails_php_apache_mysql_on_leopard/</link>
		<comments>http://www.limboy.com/2007/11/14/rails_php_apache_mysql_on_leopard/#comments</comments>
		<pubDate>Wed, 14 Nov 2007 04:21:37 +0000</pubDate>
		<dc:creator>Dexter.Yy</dc:creator>
				<category><![CDATA[Apple]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[代码]]></category>

		<guid isPermaLink="false">http://www.limboy.com/2007/11/14/rails_php_apache_mysql_on_leopard/</guid>
		<description><![CDATA[上上周在lex的怂恿下升级到了Leopard，最后花了3天时间，备份数据用了一台macbook pro加一只80g移动硬盘，重装4遍，到现在总算稳定下来了，不过还有一个bug未解决（期待10.5.1补丁）……
在Leopard里，很多开源代码都升级到了最新版，比如Python 2.5.1，PHP 5.2.4，Ruby 1.8.6，Apache 2.2，更棒的是，这次系统里直接集成了ruby on rails，包括Mongrel和Capistrano，据说还做过优化……
以前在mac里配置ROR，我是按照Dan Benjamin的《Building Ruby, Rails, Subversion, Mongrel, and MySQL on Mac OS X》来做的，安装ruby,gem之类的东西都是依靠MacPorts（osx里的包管理系统），而MacPorts安装的程序都在/opt/local里，独立于系统环境……
作为一个完美主义者，一定不能容忍自己心爱的系统里有任何兀余的代码，所以，这一次我希望能在leopard已经集成的代码基础上，搭建rails+php+apache+mysql的开发环境……
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;完美主义者的分割线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-
首先搞定apache，在配置面板里的“共享”中，选中&#8221;web共享&#8221;，就可以启动apache。默认的http://localhost指向/Library/WebServer/Documents，如果想修改成自己的目录，比如/Users/dexteryy/Sites/www，最简单的方法是直接改掉httpd.conf里的DocumentRoot
httpd.conf是放在/etc/apache2/里的，除了DocumentRoot，还要记得把下面两行代码前的注释删掉：
LoadModule php5_module        libexec/apache2/libphp5.so
LoadModule fastcgi_module     libexec/apache2/mod_fastcgi.so
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;完美主义者的分割线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-
然后是php.ini，系统默认在/etc里放了一个php.ini.default，把它copy一份，改名为php.ini
php.ini里有一个关于mysql的地方要注意，leopard好像修改过mysql.sock的位置，所以要修改以下两行：
mysql.default_socket = /private/tmp/mysql.sock
mysqli.default_socket = /private/tmp/mysql.sock
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;完美主义者的分割线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-
然后安装最新的mysql，我下载的是mysql-5.0.45-osx10.4-i686.dmg。其中的MySQLStartupItem.pkg和mysql.prefpane都不用安装了，因为这两个东西目前都不起作用-___-b
以前启动mysql都是用这个命令：
sudo /Library/StartupItems/MySQLCOM/MySQLCOM start
但是在leopard里，这个东西好像失效了，只好用这个命令来启动
sudo /usr/local/mysql/bin/safe_mysqld
如果要自动启动mysql，可以用以下方法：
在/Library/LaunchDaemons/里新建一个叫com.mysql.mysqld.plist的文件：
&#60;?xml version=&#34;1.0&#34; encoding=&#34;UTF-8&#34;?&#62;
&#60;!DOCTYPE&#160;plist PUBLIC &#34;-//Apple//DTD PLIST 1.0//EN&#34; &#34;http://www.apple.com/DTDs/PropertyList-1.0.dtd&#34;&#62;
&#60;plist&#160;version=&#34;1.0&#34;&#62;
&#60;dict&#62;
&#160; &#160; &#60;key&#62;KeepAlive&#60;/key&#62;
&#160; &#160; &#60;true/&#62;
&#160; &#160; &#60;key&#62;Label&#60;/key&#62;
&#160; &#160; [...]]]></description>
			<content:encoded><![CDATA[<p><a href='http://www.limboy.com/2007/11/14/rails_php_apache_mysql_on_leopard/leopard_box200jpg/' rel='attachment wp-att-154' title='leopard_box200.jpg'><img src='http://www.limboy.com/wp-content/uploads/2007/11/leopard_box200.jpg' alt='leopard_box200.jpg' style="float:left;margin:0 10px 5px 0;width:150px;" /></a>上上周在lex的怂恿下升级到了Leopard，最后花了3天时间，备份数据用了一台macbook pro加一只80g移动硬盘，重装4遍，到现在总算稳定下来了，不过还有一个bug未解决（期待10.5.1补丁）……</p>
<p>在Leopard里，很多开源代码都升级到了最新版，比如Python 2.5.1，PHP 5.2.4，Ruby 1.8.6，Apache 2.2，更棒的是，这次系统里直接集成了ruby on rails，包括<a href="http://mongrel.rubyforge.org/">Mongrel</a>和Capistrano，据说还做过优化……</p>
<p>以前在mac里配置ROR，我是按照Dan Benjamin的<a href="http://hivelogic.com/narrative/articles/ruby-rails-mongrel-mysql-osx">《Building Ruby, Rails, Subversion, Mongrel, and MySQL on Mac OS X》</a>来做的，安装ruby,gem之类的东西都是依靠<a href="http://www.macports.org/">MacPorts</a>（osx里的包管理系统），而MacPorts安装的程序都在/opt/local里，独立于系统环境……</p>
<p>作为一个完美主义者，一定不能容忍自己心爱的系统里有任何兀余的代码，所以，这一次我希望能在leopard已经集成的代码基础上，搭建rails+php+apache+mysql的开发环境……<span id="more-153"></span></p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;完美主义者的分割线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>首先搞定apache，在配置面板里的“共享”中，选中&#8221;web共享&#8221;，就可以启动apache。默认的http://localhost指向/Library/WebServer/Documents，如果想修改成自己的目录，比如/Users/dexteryy/Sites/www，最简单的方法是直接改掉httpd.conf里的DocumentRoot</p>
<p>httpd.conf是放在/etc/apache2/里的，除了DocumentRoot，还要记得把下面两行代码前的注释删掉：</p>
<p>LoadModule php5_module        libexec/apache2/libphp5.so<br />
LoadModule fastcgi_module     libexec/apache2/mod_fastcgi.so</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;完美主义者的分割线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>然后是php.ini，系统默认在/etc里放了一个php.ini.default，把它copy一份，改名为php.ini</p>
<p>php.ini里有一个关于mysql的地方要注意，leopard好像修改过mysql.sock的位置，所以要修改以下两行：</p>
<p>mysql.default_socket = /private/tmp/mysql.sock</p>
<p>mysqli.default_socket = /private/tmp/mysql.sock</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;完美主义者的分割线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>然后安装最新的mysql，我下载的是mysql-5.0.45-osx10.4-i686.dmg。其中的MySQLStartupItem.pkg和mysql.prefpane都不用安装了，因为这两个东西目前都不起作用-___-b</p>
<p>以前启动mysql都是用这个命令：</p>
<p>sudo /Library/StartupItems/MySQLCOM/MySQLCOM start</p>
<p>但是在leopard里，这个东西好像失效了，只好用这个命令来启动</p>
<p>sudo /usr/local/mysql/bin/safe_mysqld</p>
<p>如果要自动启动mysql，可以用以下方法：</p>
<p>在/Library/LaunchDaemons/里新建一个叫com.mysql.mysqld.plist的文件：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Olive;">&lt;?</span><span style="color: Green;">xml</span><span style="color: Gray;"> </span><span style="color: #00008b;">version</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">1.0</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: #00008b;">encoding</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">UTF-8</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">?&gt;</span></li>
<li><span style="color: Olive;">&lt;</span><span style="color: Gray;">!</span><span style="color: #00008b;">DOCTYPE</span><span style="color: Gray;">&nbsp;</span><span style="color: #00008b;">plist</span><span style="color: Gray;"> </span><span style="color: #00008b;">PUBLIC</span><span style="color: Gray;"> </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">-//Apple//DTD PLIST 1.0//EN</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">http://www.apple.com/DTDs/PropertyList-1.0.dtd</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">&gt;</span></li>
<li><span style="color: Olive;">&lt;</span><span style="color: Green;">plist</span><span style="color: Gray;">&nbsp;</span><span style="color: #00008b;">version</span><span style="color: Gray;">=</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">1.0</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">&gt;</span></li>
<li><span style="color: Olive;">&lt;</span><span style="color: Green;">dict</span><span style="color: Olive;">&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">&lt;</span><span style="color: Green;">key</span><span style="color: Olive;">&gt;</span><span style="color: Gray;">KeepAlive</span><span style="color: Olive;">&lt;/</span><span style="color: Green;">key</span><span style="color: Olive;">&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">&lt;</span><span style="color: Green;">true</span><span style="color: Olive;">/&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">&lt;</span><span style="color: Green;">key</span><span style="color: Olive;">&gt;</span><span style="color: Gray;">Label</span><span style="color: Olive;">&lt;/</span><span style="color: Green;">key</span><span style="color: Olive;">&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">&lt;</span><span style="color: Green;">string</span><span style="color: Olive;">&gt;</span><span style="color: Gray;">com.mysql.mysqld</span><span style="color: Olive;">&lt;/</span><span style="color: Green;">string</span><span style="color: Olive;">&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">&lt;</span><span style="color: Green;">key</span><span style="color: Olive;">&gt;</span><span style="color: Gray;">Program</span><span style="color: Olive;">&lt;/</span><span style="color: Green;">key</span><span style="color: Olive;">&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">&lt;</span><span style="color: Green;">string</span><span style="color: Olive;">&gt;</span><span style="color: Gray;">/usr/local/mysql/bin/mysqld_safe</span><span style="color: Olive;">&lt;/</span><span style="color: Green;">string</span><span style="color: Olive;">&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">&lt;</span><span style="color: Green;">key</span><span style="color: Olive;">&gt;</span><span style="color: Gray;">RunAtLoad</span><span style="color: Olive;">&lt;/</span><span style="color: Green;">key</span><span style="color: Olive;">&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Olive;">&lt;</span><span style="color: Green;">true</span><span style="color: Olive;">/&gt;</span></li>
<li><span style="color: Olive;">&lt;/</span><span style="color: Green;">dict</span><span style="color: Olive;">&gt;</span></li>
<li><span style="color: Olive;">&lt;/</span><span style="color: Green;">plist</span><span style="color: Olive;">&gt;</span></li></ol></div>
<p>修改权限：<br />
sudo chown root /Library/LaunchDaemons/com.mysql.mysqld.plist</p>
<p>ok了……注意，如果安装过MySQLStartupItem.pkg，最好把MYSQLCOM直接删掉：</p>
<p>sudo rm -R /Library/StartupItems/MYSQLCOM</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;完美主义者的分割线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>ruby on rails已经完美的集成了，不需要做任何设置，除了跟mysql的绑定……</p>
<p>sudo gem install mysql &#8212; &#8211;with-mysql-dir=/usr/local/mysql</p>
<p>选择3……</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;完美主义者的分割线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>现在可以新建rails的项目了，在终端里进入刚才设置的DocumentRoot目录，输入/rails rails_test</p>
<p>然后启动服务器：<br />
rails_test/script/server</p>
<p>命令执行后不要关闭终端窗口（会关闭服务器），leopard的终端现在支持标签了，苹果键＋T，继续做别的事情……</p>
<p>现在访问http://localhost:3000/ ，就可以看到rails项目的页面了……</p>
<p>这里启动的服务器是Mongrel，实际上可以把它跟apache整合到一起，用apache接受浏览器的请求，利用反向代理功能转发给Mongrel，这样就不需要用3000端口，直接用这样的地址就可以访问rails的页面：http://localhost/rails_test</p>
<p>方法很简单，找到刚才的httpd.conf，在最下面加入：</p>
<p>ProxyPass /rails_test http://localhost:3000</p>
<p>&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;完美主义者的分割线&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-</p>
<p>以上是我目前搭建的一个简单的rails+php+apache+mysql开发环境，可能还有其他问题，在具体使用中慢慢改……</p>
]]></content:encoded>
			<wfw:commentRss>http://www.limboy.com/2007/11/14/rails_php_apache_mysql_on_leopard/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>DOM加载事件的终极解决方案</title>
		<link>http://www.limboy.com/2007/04/19/domready/</link>
		<comments>http://www.limboy.com/2007/04/19/domready/#comments</comments>
		<pubDate>Wed, 18 Apr 2007 17:08:37 +0000</pubDate>
		<dc:creator>Dexter.Yy</dc:creator>
				<category><![CDATA[Ajax]]></category>
		<category><![CDATA[JavaScript]]></category>

		<guid isPermaLink="false">http://www.limboy.com/2007/04/19/domready/</guid>
		<description><![CDATA[今天被土豆网的lex鄙视了，因为我的BLOG在Safari里根本无法浏览——loading永远不会结束，很明显，这意味着webkit引擎不支持上次提到的判断DOM加载完成的方法。
既然开了新文章，就干脆重新回顾一下这个问题：如今的javascript编程非常依赖DOM（文档对象模型），对HTML和XML来说，DOM是一个应用程序接口 (API) ，对JS来说，DOM为文档创建了程序可以使用的对象和方法，DOM把前端程序和内容结合在一起，就好像ORM（对象-关系映射，比如PEAR库里的DB_DataObject）把后台程序和关系数据库结合在一起，形象点说它是一颗节点树，没有这棵树的支撑，很多JS方法就无法使用。
传统方式是通过window.onload事件来判断DOM是否加载完成，但实际上它的加载时间里还包括了img标签插入的图片、FLASH等大家伙，很多时候，来不及等这些东西都下载完成才执行JS（特别是当你要用JS给页面元素注册事件、调整外观，用AJAX加载重要内容）。所以必须有一种方法来单独判断DOM是否加载完成。
国外很早就有强者解决了这个问题，但我上次看的资料其实不完整（不求甚解的下场），最终的解决方案是在几个人的BLOG上讨论出来的……blogsphere（博客圈）果然是一种能激发创造性的社区结构……
首先是Dean Edwards指出了两件重要的工具：

Mozilla提供一个很棒的事件：DOMContentLoaded
微软支持defer属性，这并不是私有属性，而是包括在W3C的DOM 1标准里的，但是它似乎没有被XHTML支持，还有一个特点是，defer只能放在script标签里，而不能用JS来添加。

那么首先在Firefox上判断DOM加载完成就很简单了：
if (document.addEventListener)&#160;
{
&#160; &#160; document.addEventListener(&#34;DOMContentLoaded&#34;, init, false);
}
Opera9也支持上面的方法，但更低版本就不行了……
至于IE，最早提出的方法是把init函数放在一个单独的ie_onload.js里执行，在HTML调用脚本时加入条件注释和defer：
&#60;!--[if IE]&#62;&#60;script defer src=&#34;ie_onload.js&#34;&#62;&#60;/script&#62;&#60;![endif]--&#62;
或者：
&#60;!--[if IE]&#62;&#60;script defer src=&#34;javascript:'init()'&#34;&#62;&#60;/script&#62;&#60;![endif]--&#62;
这个方法的缺点是要在HTML里嵌入代码，缺乏灵活性，在Matthias Miller加入讨论后，产生了更方便的实现方法：
// for Internet Explorer
&#160; &#160; &#160; /*@cc_on @*/
&#160; &#160; &#160; /*@if (@_win32)
&#160; &#160; &#160; &#160; &#160; document.write(&#34;&#60;scr&#34;+&#34;ipt id=__ie_onload defer src=//0&#62;&#60;\/scr&#34;+&#34;ipt&#62;&#34;);
&#160; &#160; &#160; &#160; &#160; var script = document.getElementById(&#34;__ie_onload&#34;);
&#160; &#160; &#160; &#160; &#160; script.onreadystatechange = function() {
&#160; &#160; &#160; &#160; [...]]]></description>
			<content:encoded><![CDATA[<p><a href='http://www.limboy.com/2007/04/19/domready/domreadyjpg/' rel='attachment wp-att-107' title='domready.jpg'><img src='http://www.limboy.com/wp-content/uploads/2007/04/domready.jpg' alt='domready.jpg' style="float:left;margin:0 10px 0 0px;" /></a>今天被土豆网的<a href="http://my.opera.com/lexrus/blog/">lex</a>鄙视了，因为我的BLOG在Safari里根本无法浏览——loading永远不会结束，很明显，这意味着webkit引擎不支持<a href="http://www.limboy.com/2007/04/04/theme/">上次提到的</a>判断DOM加载完成的方法。</p>
<p>既然开了新文章，就干脆重新回顾一下这个问题：如今的javascript编程非常依赖DOM（文档对象模型），对HTML和XML来说，DOM是一个应用程序接口 (API) ，对JS来说，DOM为文档创建了程序可以使用的对象和方法，DOM把前端程序和内容结合在一起，就好像ORM（对象-关系映射，比如<a href="http://www.pearchina.com/">PEAR库</a>里的DB_DataObject）把后台程序和关系数据库结合在一起，形象点说它是一颗节点树，没有这棵树的支撑，很多JS方法就无法使用。<span id="more-106"></span></p>
<p>传统方式是通过window.onload事件来判断DOM是否加载完成，但实际上它的加载时间里还包括了img标签插入的图片、FLASH等大家伙，很多时候，来不及等这些东西都下载完成才执行JS（特别是当你要用JS给页面元素注册事件、调整外观，用AJAX加载重要内容）。所以必须有一种方法来单独判断DOM是否加载完成。</p>
<p>国外很早就有强者解决了这个问题，但我上次看的资料其实不完整（不求甚解的下场），最终的解决方案是在几个人的BLOG上讨论出来的……blogsphere（博客圈）果然是一种能激发创造性的社区结构……</p>
<p>首先是<a href="http://dean.edwards.name/weblog/2005/09/busted/">Dean Edwards</a>指出了两件重要的工具：</p>
<ul>
<li>Mozilla提供一个很棒的事件：DOMContentLoaded</li>
<li>微软支持<a href="http://msdn.microsoft.com/workshop/author/dhtml/reference/properties/defer.asp">defer</a>属性，这并不是私有属性，而是包括在W3C的DOM 1标准里的，但是它似乎没有被XHTML支持，还有一个特点是，defer只能放在script标签里，而不能用JS来添加。</li>
</ul>
<p>那么首先在Firefox上判断DOM加载完成就很简单了：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Green;">if</span><span style="color: Gray;"> </span><span style="color: Olive;">(</span><span style="color: Teal;">document</span><span style="color: Gray;">.</span><span style="color: Blue;">addEventListener</span><span style="color: Olive;">)</span><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; </span><span style="color: Teal;">document</span><span style="color: Gray;">.</span><span style="color: Blue;">addEventListener</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">DOMContentLoaded</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Blue;">init</span><span style="color: Gray;">, </span><span style="color: Green;">false</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Olive;">}</span></li></ol></div>
<p>Opera9也支持上面的方法，但更低版本就不行了……</p>
<p>至于IE，最早提出的方法是把init函数放在一个单独的ie_onload.js里执行，在HTML调用脚本时加入条件注释和defer：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: #ffa500;">&lt;!--[if IE]&gt;&lt;script defer src=&quot;ie_onload.js&quot;&gt;&lt;/script&gt;&lt;![endif]--&gt;</span></li></ol></div>
<p>或者：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: #ffa500;">&lt;!--[if IE]&gt;&lt;script defer src=&quot;javascript:'init()'&quot;&gt;&lt;/script&gt;&lt;![endif]--&gt;</span></li></ol></div>
<p>这个方法的缺点是要在HTML里嵌入代码，缺乏灵活性，在<a href="http://www.outofhanwell.com/blog/index.php?title=the_window_onload_problem_revisited">Matthias Miller</a>加入讨论后，产生了更方便的实现方法：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: #ffa500;">// for Internet Explorer</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">/*@cc_on @*/</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">/*@if (@_win32)</span></li>
<li><span style="color: #ffa500;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; document.write(&quot;&lt;scr&quot;+&quot;ipt id=__ie_onload defer src=//0&gt;&lt;\/scr&quot;+&quot;ipt&gt;&quot;);</span></li>
<li><span style="color: #ffa500;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var script = document.getElementById(&quot;__ie_onload&quot;);</span></li>
<li><span style="color: #ffa500;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; script.onreadystatechange = function() {</span></li>
<li><span style="color: #ffa500;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (this.readyState == &quot;complete&quot;) {</span></li>
<li><span style="color: #ffa500;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; init(); // call the onload handler</span></li>
<li><span style="color: #ffa500;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }</span></li>
<li><span style="color: #ffa500;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; };</span></li>
<li><span style="color: #ffa500;">&nbsp; &nbsp; &nbsp; /*@end @*/</span></li></ol></div>
<p>这里的cc就是conditional compilation（条件编译），跟条件注释很像，具体介绍可以看<a href="http://bbs.blueidea.com/redirect.php?tid=2453449&#038;goto=lastpost&#038;highlight=">这里翻译的文章</a>。这里使用CC是因为内部的代码会引起非IE浏览器的错误（比如Safari会出错）</p>
<p>而“script&#8221;被拆成&#8221;scr&#8221;+&#8221;ipt&#8221;似乎是为了避免与诺顿（Norton Internet Security）发生冲突-_____-b</p>
<p>如果你以为这样就可以应付所有情况了，就会像我一样被Safari用户鄙视……</p>
<p>jQuery的创始人John Resig在邮件列表里给出了Safari的解决方法：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: #ffa500;">// for Safari</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Green;">if</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">(</span><span style="color: #8b0000;">/</span><span style="color: Red;">WebKit</span><span style="color: #8b0000;">/i</span><span style="color: Gray;">.</span><span style="color: Blue;">test</span><span style="color: Olive;">(</span><span style="color: Teal;">navigator</span><span style="color: Gray;">.</span><span style="color: Blue;">userAgent</span><span style="color: Olive;">))</span><span style="color: Gray;"> </span><span style="color: Olive;">{</span><span style="color: Gray;"> </span><span style="color: #ffa500;">// sniff</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Teal;">window</span><span style="color: Gray;">.</span><span style="color: Blue;">__load_timer</span><span style="color: Gray;"> = </span><span style="color: Blue;">setInterval</span><span style="color: Olive;">(</span><span style="color: Green;">function</span><span style="color: Olive;">()</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">if</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">(</span><span style="color: #8b0000;">/</span><span style="color: Red;">loaded|complete</span><span style="color: #8b0000;">/</span><span style="color: Gray;">.</span><span style="color: Blue;">test</span><span style="color: Olive;">(</span><span style="color: Teal;">document</span><span style="color: Gray;">.</span><span style="color: Blue;">readyState</span><span style="color: Olive;">))</span><span style="color: Gray;"> </span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">init</span><span style="color: Olive;">()</span><span style="color: Gray;">; </span><span style="color: #ffa500;">// call the onload handler</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">}</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">}</span><span style="color: Gray;">, </span><span style="color: Maroon;">10</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">}</span></li></ol></div>
<p>最后有人封装了完整的代码：</p>
<div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: #ffa500;">/*</span></li>
<li><span style="color: #ffa500;"> * (c)2006 Dean Edwards/Matthias Miller/John Resig</span></li>
<li><span style="color: #ffa500;"> * Special thanks to Dan Webb's domready.js Prototype extension</span></li>
<li><span style="color: #ffa500;"> * and Simon Willison's addLoadEvent</span></li>
<li><span style="color: #ffa500;"> *</span></li>
<li><span style="color: #ffa500;"> * For more info, see:</span></li>
<li><span style="color: #ffa500;"> * </span><span style="color: Blue;">http://dean.edwards.name/weblog/2006/06/again/</span></li>
<li><span style="color: #ffa500;"> * </span><span style="color: Blue;">http://www.vivabit.com/bollocks/2006/06/21/a-dom-ready-extension-for-prototype</span></li>
<li><span style="color: #ffa500;"> * </span><span style="color: Blue;">http://simon.incutio.com/archive/2004/05/26/addLoadEvent</span></li>
<li><span style="color: #ffa500;"> * </span></li>
<li><span style="color: #ffa500;"> * Thrown together by Jesse Skinner (</span><span style="color: Blue;">http://www.thefutureoftheweb.com/</span><span style="color: #ffa500;">)</span></li>
<li><span style="color: #ffa500;"> *</span></li>
<li><span style="color: #ffa500;"> *</span></li>
<li><span style="color: #ffa500;"> * To use: call addDOMLoadEvent one or more times with functions, ie:</span></li>
<li><span style="color: #ffa500;"> *</span></li>
<li><span style="color: #ffa500;"> *&nbsp; &nbsp; function something() {</span></li>
<li><span style="color: #ffa500;"> *&nbsp; &nbsp; &nbsp;&nbsp; // do something</span></li>
<li><span style="color: #ffa500;"> *&nbsp; &nbsp; }</span></li>
<li><span style="color: #ffa500;"> *&nbsp; &nbsp; addDOMLoadEvent(something);</span></li>
<li><span style="color: #ffa500;"> *</span></li>
<li><span style="color: #ffa500;"> *&nbsp; &nbsp; addDOMLoadEvent(function() {</span></li>
<li><span style="color: #ffa500;"> *&nbsp; &nbsp; &nbsp; &nbsp; // do other stuff</span></li>
<li><span style="color: #ffa500;"> *&nbsp; &nbsp; });</span></li>
<li><span style="color: #ffa500;"> *</span></li>
<li><span style="color: #ffa500;"> */</span></li>
<li><span style="color: Gray;">&nbsp;</span></li>
<li><span style="color: Green;">function</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">addDOMLoadEvent</span><span style="color: Olive;">(</span><span style="color: Blue;">func</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp;&nbsp; </span><span style="color: Green;">if</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">(</span><span style="color: Gray;">!</span><span style="color: Teal;">window</span><span style="color: Gray;">.</span><span style="color: Blue;">__load_events</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Green;">var</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">init</span><span style="color: Gray;"> = </span><span style="color: Green;">function</span><span style="color: Gray;"> </span><span style="color: Olive;">()</span><span style="color: Gray;"> </span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">// quit if this function has already been called</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">if</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">(</span><span style="color: Blue;">arguments</span><span style="color: Gray;">.</span><span style="color: Blue;">callee</span><span style="color: Gray;">.</span><span style="color: Blue;">done</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Green;">return</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">// flag this function so we don't do the same thing twice</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">arguments</span><span style="color: Gray;">.</span><span style="color: Blue;">callee</span><span style="color: Gray;">.</span><span style="color: Blue;">done</span><span style="color: Gray;"> = </span><span style="color: Green;">true</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">// kill the timer</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">if</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">(</span><span style="color: Teal;">window</span><span style="color: Gray;">.</span><span style="color: Blue;">__load_timer</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Olive;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">clearInterval</span><span style="color: Olive;">(</span><span style="color: Teal;">window</span><span style="color: Gray;">.</span><span style="color: Blue;">__load_timer</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Teal;">window</span><span style="color: Gray;">.</span><span style="color: Blue;">__load_timer</span><span style="color: Gray;"> = </span><span style="color: Green;">null</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">}</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">// execute each function in the stack in the order they were added</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">for</
