学习模板引擎基本原理
22 May 2017
之前看了 小胡子哥 关于模板引擎原理的博文,对模板引擎有了大致的理解,重新来看这篇文章,又有了点思考。这里我做一下整理。
最开始,我们遇到要拼装dom的时候,都是很简单的字符串拼装,比如
这种写起来好像没啥问题,但写多了挺烦的,dom结构一长,要渲染的数据一多,就要想方法做函数封装以及代码优化。
而模板引擎会省心很多,说起模板引擎,其实现的主要功能有几点:变量替换、条件判断、对象遍历。
从上面的字符串拼装代码可以看出,主要字符串拼装就是实现变量替换(replace
正则替换)。
所以刚开始实现可以这么写:
但是这么写,不支持子对象,即
虽然可以这么写:
不过,这个就跟后面条件判断以及对象遍历思路没啥联系了。
反观,胡子哥的做法,则是在拼装字符串时,用到变量替换的部分还是照常用js变量代码:return data.name + '说:他想学'+ data.study.name;
这样就要考虑组装字符串以及结合js变量的情形,想想,对于<%name%>说:他想学<% study.name %>
这样的模板,是不是要处理成name + "说:他想学"+ study.name
,因为这里要从字符串转成字符串拼接以及js代码,也就是字符串变成js代码,所以需要用new Function
,尝试用前者实现一下
看代码好像组装完毕了,但是执行时肯定会报错,因为代码里引用的js变量未定义, 那我们可以将传入的data遍历并直出到构造函数的代码字符串中(变量声明),也就可以了。
其实这里实现已经提示出条件判断跟对象遍历了,实际上在讲模板转化成一个js代码字符串时,就是将属于js代码的部分原封不动的保留,将非代码部分构造成字符串拼接,最终执行这个js代码字符串。
模板:
转成函数代码:
对比可以看出,可以利用正则,不断匹配模板内的<%%>
,如果内容包含for
等关键词,则原样输出,如果是变量则r.push(变量)
,其他则都是直接r.push(xxxx)
。
最终r组装成字符串,并用Function
构造函数并执行。
我们来看胡子哥的实现:
这里最后用了apply(data)
,将构建的function绑定this作用域,不过这样有个局限性,那就是模板内引用数据变量需要加上this.
,不然同样是找不到对应的变量报错。
这里可以结合前面第一次拼装function字符串的实现,将传入的data一并进行var
声明的内容拼装到字符串中。
这样就即可以模板引用变量用this.
也可以不用了。
在实现这个数据声明构造时,踩过一个坑,那就是,一开始觉得直接JSON.stringify
把data整一个都转成字符串,然后去掉最外层的尖括号,然后分割逗号变成数组,再把第一个冒号替换成等号,说个引号包裹单词去掉引号,最后组装回来。
但这样遇到子对象内有逗号时分割就受到干扰了!
总结一下,模板引擎的思路就是,js函数的拼装以及构造函数和变量声明以及作用域绑定,貌似但凡涉及到字符串替换的,正则是少不了的,正则大法好,个人的正则启蒙传送门