#BackboneConf2012 How to Argue about Javascript by Andrew Dupont

Backbone Conf 2012

有幸去美国波士顿参加了2012年的 Backbone.js Conference,见到了coffeescriptunderscore.js 还有 backbone.js 的作者 Jeremy Ashkenas。会议内容围绕前端MVWTF和社区进行了很多有趣的讨论,有很多有价值的观点。我希望在这里面与大家分享我从里面学到的东西。

这系列博客其实是我整理的会议笔记的汇总,是我对每个话题中比较有印象或者比较重要的内容的摘抄,这些观点几乎都不是我的,我仅作为一个传声者。我是希望把所有的Credit交给演讲者自己,我最多只是一个翻译者,碰巧幸运的在现场。Backbone.js Conference和O’Reilly的Fluent Conference 碰巧同时进行,#BackboneConf 更加草根,但是也更有观点。

How to Argue about Javascript by Andrew Dupont

Andrew Dupont

Links

Notes

Andrew说话比较慢(尤其是没有预先准备的时候),但是他的语言很睿智。他的话题也很睿智,讲的不是具体的框架或者技术,而是软技巧“如何争论?”。他讨论了如何好好的辩论,而如何辩论是不好的。

核心的事件就是社区内火热的Semicolon问题~

How not to argue about semicolons?

  • Our arguments should be purposeful

要有目的,就是说为了解决实际的问题。比如科学研究符合这点,不过很多政治争论不符合这点(政见之争是狗屁?)。他引用了Carl Sagan说的一段话,大意是科学家比较可能会放弃自己的立场并被说服,但是政治和宗教之争很难看到放下武器站到对方一边的场景。

这些是常见的一些场景:

  • “Whoe the hell are you?” – 你微不足道
  • “Whre do you get off censoring me, you fascist?” – 你凭什么管我,你个法西斯
  • Motives for having a code argument:那么我们为什么在代码问题上争论呢?

其实不应该是为了显摆你自己,也不应该为了说服别人认同你的想法。

争论的目的应该是更好的了解你们争论的主题

有一本很有名的书叫”Getting to yess”,副标题是Negotiating agreement without giving in。

An argument has 3 goals:

  • It should produce a wise agreement, if possible 应该达成聪明的一致
  • It should be efficient 有效率
  • It should not damage the relationship between parties 不破坏各方的关系

Tactics for arguments: 争论的战术

  • Separate the people from the problem 就事不对人,必须区分问题的目的(本质)和你对这件事的情感因素
  • Focus on interests, not positions 注重共同的利益,而不是自己的立场(位置)
  • Invent options for mutual gain 创造一些方案来达到共同受益
  • Insist on objective criteria 只坚持客观的条件(如标准、benchmarks)

这个例子很逗,分号之争来自github上面的一个bug。有人报了bug,然后 @fat 说这不是他代码的bug,而是 JSMIN 的bug。然后 douglas crockford大神 蹦出来说这不是 JSMIN 的bug,而是 @fat 对js分隔符理解有问题(其实不完全是),然后 @fat 就反驳说我就这样写你怎么地吧?

zzzzing! 这梁子就算是结上了!

另外一个例子是Selector引擎战争,这源自moo.tools作者写的一个benchmark,职责JQuery的selector引擎比较弱,因为它的选择器在这个benchmark的很多场景下都是比较慢的。

然后John Resig就写了一篇犀利的博客 “Selectors that people actually use“,职责这个benchmark里面的很多场景并非人类常用……

那我们应该怎样办呢?我们应该以愿意被说服的态度去讨论,思考对方为什么持不同的简介,考虑品味的不同,考虑情绪的问题。

他举了John的另外一个例子,他如何回答 “JQuery steals code” 和 “JQuery hates developers, love companies” 这两个问题。他的博客犀利、幽默,是解决这种问题的一个典范。他没有直接争论,而是用有趣的方式去化解自己的被动。

后面回到例子的主线,就是Bootstrap是否应该为了 JSMIN 去增加一个分号呢?库的作者是否应该为了 JSMIN 兼容性去做一些让步呢?还是 JSMIN 应该主动改变(Crockford 觉得那样做很没品)。

有趣的句子:

“People who don’t use semicolons are Javascript hipsters.”

“No, people who are fanatical about semicolons are just spreading FUD.”

“@fat is being a jackass and a bad project steward.”

“No, people like you are bitching about a library they got for free.”

“Semicolon or not, that line should still be rewritten.”

“JSMin sucks anyway. People should use some other minifier.”

“Who cares about minification? Everyone’s got a fast connection now.”

争论愈演愈烈,慢慢变成各种人身攻击和开玩笑,很多人抱怨这个ticket不停的给他发邮件……

最搞笑的是 @fat 本人在中间留言,新版的Bootstrap已经修正了这个问题了……后面还是继续 shit storm

但是后面还是各种人身攻击……

作者用了一个特别贴切的形容词”Shit-storm”!

这说明跑题了,如何不跑题呢?

要温和一些(和谐),be nice! 说话要精确,不要扫射……

作者举了一些委婉的表达的例子……很委婉。

javascript社区还有很多例子

  • Ember vs. Backbone
  • Mico-frameworks
  • Coffeescript!
  • Douglas Crockford vs. the world 这个是开玩笑的

总的来说,社区里面争论真的是一个非常重要的事情,避免Shit-storm的发生对社区有益。

知乎里面就有这个争论的延伸,虽然这里没有脏字,但是大部分人也一样是被卷入这个争论……

我的回答:

加与不加是风格问题,风格争议不需要有个定论。关键的问题在于如何“争论”,处理好冲突,学会组织语言减少争议是最重要的。因为分号问题在社区内部造成了很多况日持久的口水战,这些口水战是社区的损失……因为大家在这个时候可以写更多的代码带来更多的功能。

#BackboneConf2012 Ember.js by Yehuda Katz

Backbone Conf 2012

有幸去美国波士顿参加了2012年的 Backbone.js Conference,见到了coffeescriptunderscore.js 还有 backbone.js 的作者 Jeremy Ashkenas。会议内容围绕前端MVWTF和社区进行了很多有趣的讨论,有很多有价值的观点。我希望在这里面与大家分享我从里面学到的东西。

这系列博客其实是我整理的会议笔记的汇总,是我对每个话题中比较有印象或者比较重要的内容的摘抄,这些观点几乎都不是我的,我仅作为一个传声者。我是希望把所有的Credit交给演讲者自己,我最多只是一个翻译者,碰巧幸运的在现场。Backbone.js Conference和O’Reilly的Fluent Conference 碰巧同时进行,#BackboneConf 更加草根,但是也更有观点。

Ember.js by Yehuda Katz

Yehuda Katz

Links

Notes

Ember.js的主力开发者和鼓吹者是Yehuda Katz,这个框架来自于他们团队所咨询的项目。所以这也是由实际需求催生的一个项目。

Ember.js expectations

  • bidirectional data binding, it’s special
  • View hierarchy
  • Structure and Widgets
  • Routing

Ember’s Bindings are backed into the object model.

bindings are always async. It guarantees you the ability to make all necessary changes before side-effects occur.

它很智能的解决了单个属性changes造成的event雪崩。若干Model set只会集中触发一次UI update。Guarantees a single DOM update per turn in the browser’s event loop.

它的Template组合方式保证子template的渲染只有一次Dom update。

它的View hierarchy也就是CompositeView处理了子View的状态清理(双向unbind,释放资源),并且提供了一些Lifecycle events(很有价值)。

Template的渲染过程隐含了Collection和Model的事件绑定,Template里面的action可以在Router触发事件并且可以生成对应的url。

Ember.js的特点就是用黑魔法(black magic,注:这是我说的,是我的偏见 ;-D)帮你默认做了很多事情,作者管这个叫“Does the right thing by default”,这是一个双刃剑。但是对于有很多雷同的页面和功能的项目来说它可以保证write less do more,并且平均的代码质量会提高(因为复杂逻辑完全被框架所封装好了)。

Backbone.js的一个重要买点是View的Stateless,而ember.js则通过Routing主动的负担起了State Management的责任。Router里面定义了系统的各种State,用户点击action或者通过URL跳转实际上是改变了状态机的状态,router定义了这些状态和状态转换。因为UI状态机实际上是一个非常复杂的建模方式,因为状态的转换组合可以让系统处于很多复杂和混乱的情境中,当然ember.js这样做也是有理由的,它的好处包括logging、对生产应用进行debugging,避免不可能的情况(通过定义所有可能的情况!)。

对于状态机这个表述,Yehuda在现场被很多“大牛”质疑了,获得了不少的嘘声。不过这的确是解决非常复杂的问题的一种标准的解决方法,但是由于这种分析方式本身(定义状态,把不同的状态正交的解开)有很大的难度,所以它有可能会让你陷身泥潭。这就是很多注重简单的MVWTF框架会选择不去管理状态,而选择Stateless的原因。

#BackboneConf2012 Keynote for BackboneConf by Jeremy Ashkenas

Backbone Conf 2012

有幸去美国波士顿参加了2012年的 Backbone.js Conference,见到了coffeescriptunderscore.js 还有 backbone.js 的作者 Jeremy Ashkenas。会议内容围绕前端MVWTF和社区进行了很多有趣的讨论,有很多有价值的观点。我希望在这里面与大家分享我从里面学到的东西。

这系列博客其实是我整理的会议笔记的汇总,是我对每个话题中比较有印象或者比较重要的内容的摘抄,这些观点几乎都不是我的,我仅作为一个传声者。我是希望把所有的Credit交给演讲者自己,我最多只是一个翻译者,碰巧幸运的在现场。Backbone.js Conference和O’Reilly的Fluent Conference 碰巧同时进行,#BackboneConf 更加草根,但是也更有观点。

Keynote for BackboneConf by Jeremy Ashkenas

The keynote

Links

Notes

  • Backbone.js成长的非常快,只用了1.5年就在社区内引起了巨大的反响
  • Backbone是来自真实的项目,满足真实的需求,这个框架只是一个副产品
  • Backbone.js是抽出DocumentCloud项目可复用的部分的产物
  • Backbone.js的用户很大牌

Backbone.js是一个small、simple、flexible的框架,所以没有典型的Backbone应用,我们现在看到的例子只是冰山的一角。

传统的JQuery的一个大的问题就是它面对的是获取文本,更新HTML上的另外一些文本。但是这个过程中我们没有明确的获取和渲染数据模型。

Avoid jQuery hell by getting your state of out of the DOM

因为JQuery更新的Dom本身就是有状态的,所以代码尝尝混杂者状态判断的逻辑,这是很让人头疼的状态。

Model is where your data lives, source of truth for application. UI only knows about the truth in the models. UI can’t conflict with others

数据模型应该表示状态,让UI与状态分离,这样UI之间就不会因为复杂的状态而纠缠不清。

在Backbone.js里面,我们修改Model的状态。而其它的组件监听Model的事件。

ClientSide的collection一般是整体Model的repository的一个子集。Model是个体,而collection是集合。他们是保持客户端状态的基础。Underscore.js用来访问Model和Collection,它是Backbone.js的魅力的体现。

Ashkenas演示了他们使用namespace,把系统中所有的Model和View实例全部都放在一个树型数据结构上,可以看到View的实例一般是绑定在相应的Collection和Model下面。这个树形数据结构保存了客户端的所有状态和实例,对于debug非常有利。View放在Collection和Model下面是因为View是无状态的(它依附于相应的Collection和Model的状态)。

Changes

一般的模式是Model被set后View就re-render,View会监听change事件。Model和Collection的save的语义是将变化传递到服务器(持久化),而set只是修改状态并触发change。

Model和Collection初始化的时候可能需要逐层载入,这个时候可能会触发多次change,可以使用参数{silent: true}。它是专门应对触发change的中间状态而设计的,当需要触发View的re-render时再trigger change事件。这样的设计可以保证View是完全无状态的。

有人问客户端Model会有一些对服务器端没有意义的属性,如selected表示一个模型是否是被选中的状态,这可以么?
因为Model是用来保存系统状态的,所以这些状态属性就应该放在Model里面。

View的更新是应该使用乐观模式还是悲观模式呢?(是否等待状态保存到服务器后再更新UI)。
这个要看场景,Instagram就做了很多这样的trick。避免状态不一致是最重要的,所以对于不太可靠的更新需要使用悲观方式。

Model之间的关系如何传递?Model的属性是否可以是collection。
可以,通过Model和它的属性间的event proxy传递event。(第二天的SuperModel,还有其它解决方案,可以用声明的方式绑定Model和sub models之间的关系,自动proxy event)

change event的listener可以通过this.get(‘prop’)和this.previous(‘prop’)来获取修改的属性的变化情况。

Views

Views should be stateless!!!

  • View is stateless if it always has a dom element at all times
  • Did my view render in a particular mode when it doesn’t exist? No, elem is always there and events are always delegated

View在它被初始化的时候它的element就应该已经存在,这样它的render和re-render就不会依赖于其它先置条件,从而保持stateless。

Backbone.js的哲学Philosophy

Take the truth out of the DOM.

  • So the only truth is the model 😀

Intentionally minimal

  • Small, Simple, Flexible

Resited Router for a while. Jeremy still thinks Router may be overreaching

Tries to be driven by use cases, not gospel. If you open ticket on GitHub without use cases, you’ll get ignored

Is Backbone.js MVC, MV+, MVP?

  • It’s MVWhatever
  • Important thing is that UI and Models are the common denominator. Build interesting UI without breaking app and build interesting business logic without breaking UI.
  • 最重要的分离是Model和View的分离,Model是保持状态的核心,View是无状态的

Statelessness

  • Backbone doesn’t do it for you
  • Exponential states of UI should be avoided. Don’t enumerate every state
    • UI因为是一种组合视图,所以它的状态是指数式增长的,所以要避免枚举UI的状态组合,保证UI是无状态的
  • Models contain state, UI listens to models, but UI doesn’t care about what is going on with rest of app

Other things discussed in this session

  • 在客户端和服务器端共享代码?Jeremy觉得这好像不是个好主意,但是在服务器和客户端建立一种Event传递机制似乎是一个可以考虑的方向。
  • 大家公认View的unload是一个痛点:大家发现View的初始化往往比较容易,但是View在不活跃或者需要被替换掉的时候如何unbind事件,如何处理已经渲染过的Dom,解除所有其它的双向依赖是个问题。因为View和子View的生命周期和他们的依赖关系目前还没有被建模,所以没有统一的解决方法。Jeremy透露目前他们的解决方法是通过namespace下面的遍历来unbind所有的sub-view,这种方法在不是非常复杂的情况下是可行的。不过由于这个公认痛点的存在,社区内大家都在尝试找到一种比较通用的简单解决方法。

Reply to “Backbone and Ember”

Boris Smus wrote a post about Backbone and Ember. Which is related to a podcast on Javascript Jabber. Which talks about:

Ember and Backbone are both promising JavaScript frameworks but have completely different philosophies. In this post, I’ll compare the two, both from a practical and philosophical perspective.

I post a reply there, and I copy the content here. I’m thinking the variations on javascript MVC recently, but I didn’t get the answer yet.

Bi-directional data binding and the view-model idea is fancy, but it still sounds like a overkill. The MVC has lots of variations, the presenter style (as Martin Fowler defined) is really good for complicated single page applications, when the state of application is hard to maintain.

Event driven UI should not bound to framework level, it should integrate into developer’s brain. So you do have the freedom to composite your whole UI in backbone by loose-coupled event protocol.

Scale the application has nothing to do with MVC framework, guess how a framework fits a project scale is not smart. I think which interaction style you choose is a key factor. When we want a sophisticated Desktop like web app we may prefer Ember’s style, that solves it in smart way. But for a Web like web app, backbone.js is enough, we should keep our own code as simple as backbone.js.

Work with a micro framework like Backbone, we can enjoy the refactory to patterns process. Since we own the flexibility, that’s awesome. I think the most dangerous result of adopting patterns is that you will not evaluate the value and trade-off of adopting patterns. YAGNI make sense here.

Reply lifesinger’s blog post: jQuery 让人…

Reply lifesinger’s blog post: jQuery 让人恋恋不舍的秘密

是pattern matching,基于消息的函数调用经常使用这样的模式。因为jQuery的functional风格,所以它使用了pattern matching来收紧api数量,效果很不错。

但是上次mootools的开发者说过jQuery的这种设计也意外的鼓励了一次使用就抛弃的代码风格,容易造成你写只为一个页面而作的代码段。这对于鼓励前端开发减少代码重复不利,从长期来看,由于js还不支持原生的pattern matching,所以jQuery这种方式也能由于api灵活降低一些代码的可读性。

Javascript库的“实现模式编程(Programming to patterns)”

今天看到了一篇很好的讲Javascript Library的文章:http://www.clientcide.com/best-practices/jquery-and-the-ajax-experience-programming-to-the-pattern-and-what-really-makes-one-framework-different-from-another/
作者是一位MooTools开发者,他写了对实现模式编程(programming to the patterns)进行了阐述。告诉我们像Prototype、MooTools这样模拟类继承并鼓励使用OO的方式组织你的代码对于你的好处。而对比的对象就是红火的JQuery。他的观点我举双手双脚同意。

JS的通用库最基本的目的是给你解决浏览器兼容性差异,让你在与浏览器兼容性的战争中给你一个巨大的后援保证。但是只提供浏览器兼容性的JS库是不会流行的,你还需要在编程模式和代码效率(Code efficiency)上提供帮助。对于我个人来讲,对语言的流畅性改造最好的就是Prototype这个库,因为它营造了一个“最小惊讶”的Ruby语言环境,让你几乎感觉到是在编写流畅的Ruby,尤其在Rails项目里面使用更让你感觉到Ruby和Javascript结合的流畅。(此处我想到了上周Cat Chen同学和我提起的“Language Oriented Programming”的概念,也许这就是它的表现吧,扩展语言减小编程中的“惊讶”)相比之下JQuery则在代码效率上做了很大功夫,这个代码效率不是指运行速度,而是单位代码完成的功能。JQuery对Dom的DSL化封装,还有对method chain的大量使用,几乎让你感觉在声明行为,所以它让非常多的对啰嗦的Dom编程厌烦的前端程序员迅速“上瘾”。但是,我们知道DSL化的JQuery还不够,因为它很好的解决了可读,但是并不一定容易维护(尤其是过度使用method chaning)。另外一个原因就是习惯使用“声明化”以后会让一些程序员忘记“抽象”和“封装”,很多JQuery都没有使用面向对象OO的方式去组织自己的代码,而是拥抱了面向过程编程,而很多人却还自我安慰说自己使用的是“函数式编程”。如果你没有做好函数抽象,那么绝大多数情况下你的JQuery code都不符合函数式编程的本意,此时你也就离抽象出可复用的“模式”越来越远了。

其实JQuery的很多UI plugins是很好的例子,尤其是支持Progressive Enhancement的JQuery UI插件,它们都很好的规定了自己的micro formats,然后根据dom的模式来组织自己的行为模式(Behavior and Patterns)。它们才是很好的对实现模式编程(programming to the patterns)的例子。缺少了对模式的抽象也就失去了在大的项目中实现代码效率(Code efficiency)的优势(因为代码复用度会下降),这对于JQuery这样一个以“Write less, Do more”为口号的库来说就失去了它最大的卖点。

所以,实际上关键的问题就是,用哪个JS库都没错,但是如何使用和形成模式才是关键。每个库组织自己的“模式化代码”的风格不一样。但是像MooTools和Prototype(还有YUI)这类基于类去组织代码的库的源代码本身就已经告诉了你如何组织你的代码,而且它们的OO实现对于任何一个熟悉OO的程序员来说都“没有惊讶”,那么你就很容易吸取他们所推荐的代码组织风格了。

最开始所引用的文章归纳了几个不面向“模式”组织代码的坏处:

  • 缺少抽象,缺少复用
  • 会形成零散的代码,修改起来成本会比较高,维护成本也就增高了
  • 不OO,不容易组织扩展

我补充一点:

  • 过程化的代码不容易测试,不使用模式的代码也会造成测试的零散,造成浪费

更新:有一点不准确,就是关于复用,其实Javascript的各种Widget库(如ExtJS、Dojo和YUI的widget库)都做到更好的复用。缺点是目前的widget库中的高级控件都严重的绑架了Dom结构,造成自己修改Dom结构比较麻烦。而没有使用Micro Formats这样的基于标准的弱耦合,这是一个很大的问题。所以由于这样的实现绑架的问题,这些Widget库不包括在上面所述的框架对比中。

关于javascript库的一个回复

我以前写过一篇说说我对moo、prototype、JQuery的看法在我的blogjava博客里面(现在我已经不更新了,完全使用这个wordpress的博客)。今天也是在Google Reader里面看到JavaEye的另外一个朋友lifesinger的一篇文章:大胆预测下几个JS框架的走势,我个人不是非常同意,所以写了如下回复,也发在我的blog吧。

完全不同意lifesinger的说法:

1、JQuery会走的比较远。因为Django会走的比较远。而且JQuery的内部设计很好,如果说它不好估计是没有理解它的核心理念。而且John Resig的确是个勤奋的福音传播者,它的js使用理念很好,所以这个库会随着它的plugins库的数量质量的双重提高,占重要位置。同时浏览器效率的的提高也会给它注上强心剂。

2、YUI的api设计不好。作为oo的库它不好,作为fp的库它更不好,所以它不会有多好。不过在widget类库里面它肯定继续占重要地位,因为YUI的widget的确兼容性很好。

3、moo我很喜欢,但是它的演化保持了小众的特点,小步前进,api设计上比较偏设计师的想法。做大型项目的时候你回发现moo没有对如何组织你的项目给很好的“风格”上的建议,所以它也就会在大型项目上哑火。

4、Ext,我看没什么大的希望了。因为它的授权问题,基本上它已经不在是开源社区友好的(它也许可以做自由软件社区友好吧)。而且作为一个UI Widget库,它并没有把可访问性放在重要的地方来重视,所以随着UI的可访问性要求的上升,它的默认皮肤带来的eyecandy估计就没法盖过usability的缺失了。

你没有提到Prototype,它目前还是js lib的第一名,随着活跃的RoR社区的继续推进,它应该还会持续足够的市场份额。而且它和JQuery同属于有强烈“风格”的库,所以即使项目很大,它还可以保证代码的可读性与可维护性,这对于很多项目来说是至关重要的。

关于dojo我不说了,以前说过:说说我对moo、prototype、JQuery的看法的回复里面有。

关于Javascript的入门图书

犀牛书绝对的过时,也绝对的不友好。在开始的时候,作为一本系统讲解javascript的书,它非常注重阐述规范,所以在那个时代它是最好的图书。但是现在,作为js技术的入门图书,我们有一些更好的从javascript的精髓和基本理念入手的图书,读完他们你就可以体会到规范为什么是这个样子,从记忆角度来说理解后的记忆要强过死记硬背,所以用这些图书入门是更好的选择。

Update: 有位Sina的同事说道犀牛书还是要有一本的,目的是作为参考书。我倒是觉得这个完全可以依靠网络,因为大部分时候我们就是想索引一下方法,或者看看方法签名和解释,这个时候通过在线服务绝对要好过翻书。服务里面gotapi是个不错的选择!

在国内看翻译的推荐看:

1、大辫子nicholas写的Javascript高级程序设计

2、John Resig写的精通Javascript (Pro javascript)

ppk on javascript这本书也不错,比较实用,但是个人感觉没有精通Javascriptt这本讲的清楚。

如果看原文可以期待:

1、John Resig的Javascript Ninja,未出版,但是有样章。

2、Js大神Douglas Crockford的Javascript The good parts.

上周和钱钱讨论Programming Ruby这本书的时候我们也持这个观点,它曾经是一本非常棒的入门书,因为那个时候它是第一本非日文的Ruby图书。但是这本经典书到了现在已经有了很多不一样的竞争者,像钱钱同学推荐的Every day scripting with ruby就更偏实践,更容易让你入ruby的门。

短小精悍的Javascript模板引擎

今天看到Jonh Resig的博客里面提到了他在他的Secrets of the JavaScript Ninja这本书里面介绍的一种简单的模板,代码如下:

// Simple JavaScript Templating
// John Resig - http://ejohn.org/ - MIT Licensed
(function(){
var cache = {};

this.tmpl = function tmpl(str, data){
// Figure out if we're getting a template, or if we need to
// load the template - and be sure to cache the result.
var fn = !/\W/.test(str) ?
cache[str] = cache[str] ||
tmpl(document.getElementById(str).innerHTML) :

// Generate a reusable function that will serve as a template
// generator (and which will be cached).
new Function("obj",
"var p=[],print=function(){p.push.apply(p,arguments);};" +

// Introduce the data as local variables using with(){}
"with(obj){p.push('" +

// Convert the template into pure JavaScript
str
.replace(/[\r\t\n]/g, " ")
.split("<%").join("\t") .replace(/((^|%>)[^\t]*)'/g, "$1\r")
.replace(/\t=(.*?)%>/g, "',$1,'")
.split("\t").join("');")
.split("%>").join("p.push('")
.split("\r").join("\\'")
+ "');}return p.join('');");

// Provide some basic currying to the user
return data ? fn( data ) : fn;
};
})();

这段代码非常简单,但是却有不少trick。而且这些trick十分的优雅(John resig一向擅长写优雅的javascript)。非常值得读一下。思路就是把一段模板引擎里面的求值代码标记出来,将其余代码用单引号包裹起来,所以代码会分为文本和求值两种部分,压入一个Array,最后join。把这个逻辑用string的形式初始化一个Function对象,然后cache起来就成为一个高效的javascript模板引擎了。不过这个引擎只有求值赋值的功能,没有更加复杂的逻辑控制如if, else, for这些循环,但是在求值部分增加一些正则判断来处理这部分逻辑也是可行的。我非常喜欢的Trimpath Javascript Template估计也是这个思路(虽然经常用,但是由于代码可读性的问题一直没有仔细阅读它的源码)。

这段代码里面的闭包用法也很不错,可以防止命名冲突和全局变量的污染,不过这个写法估计大家都比较熟悉了。

模板的用法就不赘述了,如果你想用这个微型模板可以看看John Resig的JavaScript Micro-Templating