语法
Underscore 的模板引擎 _.template() 脱胎于 jQuery 作者的作品 Micro-Templating。但从 Underscore 1.3.3 开始,这个方法做了较大的调整,在保留旧语法的基础上,还新增支持了一个 {variable: 'foo'}对象作为第三个参数。
一旦传入了这个参数,则模板(第一个参数)中的变量将不再指向待渲染数据(第二个参数)的属性,模板中的 foo 变量将直接指向待渲染数据(第二个参数)自身。
比如,原来的调用方法:
_.template('I love .', {person: 'you'});
在新语法下可以写为:
_.template('I love .', {person: 'you'}, {variable: 'foo'});
比较
看起来似乎变复杂了,但这样做有两个好处:
内部实现
旧语法在实现上,需要使用 with 声明来实现对数据对象属性的查找。with 有哪些问题,这里就不多说了。而新语法由于已经在模板中指定了数据对象自身,则不需要用 with 来搜索其属性。据官方文档称,“模板渲染性能得到极大提升”。
外部接口
新语法带来了一个隐性的改良——接口灵活性更高,即待渲染数据(第二个参数)可以不仅是对象,也可以是数组等其它数据类型。仍然以上面的代码为例,用新语法还可以写成这样:
_.template('I love .', 'you', {variable: 'foo'});
这样传入的数据更自由,数组等数据不需要被包装为对象再传入了。
使用
在实际应用中,往往存在某个常用的模板需要被多次渲染的情况。此时,为优化性能,我们通常会采用“两步渲染法”——先把模板编译成模板函数备用;按需执行已经编译好的模板函数,把不同的数据渲染为不同的结果——以避免同一模板的重复编译。如下所示:
var fnRender = _.template('I love .'); fnRender({person: 'you'}); //'I love you.' fnRender({person: 'her'}); //'I love her.'
在这种情况下,我们无法使用 {variable: 'foo'} 参数。那怎么办呢?
幸好有 _.templateSettings 可以进行 _.template() 的全局设置:
_.extend(_.templateSettings, {variable: 'foo'});
在此之后编译的所有模板函数即工作在新语法之下。需要注意的是,这个设置是全局的,也就是说,当前页面的所有模板和相关功能都需要以新语法来写,并将 foo 统一命名。
更新
从 Underscore 1.7 开始,这个 API 的行为又发生了一些变化,我们有必要再来看一看。
从这个版本开始,_.template() 方法将不再接受模板数据了,它的返回值就总是编译生成的模板函数了。也就是说原先一步渲染模板的用法需要修改成两步走:
// before _.template('I love .', {person: 'you'}); // after _.template('I love .')({person: 'you'});
看起来很蛋疼?无关痛痒?其实 Underscore 下决心引入这个 “破坏性变更” 还是很有深意的。我认为这个改动的好处在于:
- 消灭了返回值的不确定性,令这个 API 的行为更易于理解。
- 去掉一步到位的用法,虽然牺牲了眼前的便利,但同时也强制使用者了解模板引擎的基本原理,一定程度上会推动使用者考虑模板缓存,进而提升应用的整体性能。
希望本文能帮助到您!
点赞+转发,让更多的人也能看到这篇内容(收藏不点赞,都是耍流氓-_-)
关注 {我},享受文章首发体验!
每周重点攻克一个前端技术难点。更多精彩前端内容私信 我 回复“教程”
原文链接:https://github.com/cssmagic/blog/issues/4