-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
underscore 系列之实现一个模板引擎(上) #63
Comments
留作日志更新 |
今天面试被虐的好惨,和我谈工程学,谈源码,去年毕业的我,都被搞的没信心了 |
@liuxinqiong 一年的时候面这个确实太难了点啦,而且面试本身也是一种双向选择,就算没有面上也不一定就是自己的损失,有可能是这家公司错过了一个有潜力的少年~ 不要气馁,以此为动力,日后还要华山论剑呢~ |
写完这个系列,后面还打算写什么吗?如果能写一个怎么封装js,如何写库的教程就好了,感觉肯定是独一无二的! |
@xjh776 写完这个系列,会写 ES6 系列,写完 ES6 系列,会写 React 系列。封装 JS 的话,可以参考这个系列的第一篇,underscore 系列之如何写自己的 underscore,因为第一篇是讲了 underscore 的代码组织方式,其中的代码就可以帮助我们用来封装库。 此外还不知道你说的库是不是指像实现轮播图、拖拽之类的库,如果是这种的话,未来如果写 DOM 系列,应该就会讲到各种效果的实战,如果你等不及的话,可以参考 https://github.com/mqyqingfeng/Wheels 这个仓库中各种效果的实现代码~~ |
快过年了,有什么打算没?🤔 @mqyqingfeng |
@mqyqingfeng 😂 我们部门20+的 HeadCount,顺便插播广告,有意向的简历可以发我 GitHub 邮箱,逃:),也提前祝 @mqyqingfeng以及所有的 GayHub 的朋友 新年快乐~ 😀 |
@mqyqingfeng 谢谢,其实是想知道如何编写框架,dom库的话,感觉很容易写,你写得那些库我大概都看了下,很标准,模式都很统一,你应该看了很多源码吧 |
大大,不打算写写ramda函数式编程么😄 |
@yangfan1992 函数式编程的内容很多,而且自己也没有怎么在项目中应用过函数式编程,现在能讲的也就只有 柯里化 和 函数组合 这种非常基础的内容,更深入的内容至少要一两年以后啦……当然,如果那个时候我依然坚持写文章的话 😀 |
@xjh776 如何编写框架的话,我暂时还没有能力帮助你啦~ 虽然未来的 React 系列会讲到 React、Redux 等的 mini 实现,但还是库的范畴~ 因为没有写过,所以也没有什么好的建议给你~ 不如去看看 Vue 的源码吧~ 直接看,可能有一点难度,可以从第一个 commit 的版本开始看起, 此外网上也有很多讲解教程能帮助到你~ |
@liuxinqiong 工程学是什么?还有和你谈源码,谈什么的源码呢? |
@mqyqingfeng 请问你一般是如何阅读源码的呢?比如应该怎么阅读vue的源码呢? |
vue的generate其实用的也是这种思想,楼主发的发的很多东西在读vue的源码里都能找到“熟悉”的感觉,可见vue的诞生其实借鉴了相当多以前框架的思想。 |
前言
underscore 提供了模板引擎的功能,举个例子:
感觉好像没有什么强大的地方,再来举个例子:
在 HTML 文件中:
JavaScript 文件中:
效果为:
那么该如何实现这样一个 _.template 函数呢?
实现思路
underscore 的 template 函数参考了 jQuery 的作者 John Resig 在 2008 年发表的一篇文章 JavaScript Micro-Templating,我们先从这篇文章的思路出发,思考一下如何写一个简单的模板引擎。
依然是以这段模板字符串为例:
John Resig 的思路是将这段代码转换为这样一段程序:
我们注意,模板其实是一段字符串,我们怎么根据一段字符串生成一段代码呢?很容易就想到用 eval,那我们就先用 eval 吧。
然后我们会发现,为了转换成这样一段代码,我们需要将
<%xxx%>
转换为xxx
,其实就是去掉包裹的符号,还要将<%=xxx%>
转化成p.push(xxx)
,这些都可以用正则实现,但是我们还需要写p.push('<li><a href="');
、p.push('">');
呐,这些该如何实现呢?那我们换个思路,依然是用正则,但是我们
%>
替换成p.push('
<%
替换成');
<%=xxx%>
替换成');p.push(xxx);p.push('
我们来举个例子:
按照这个替换规则会被替换为:
这样肯定会报错,毕竟代码都没有写全,我们在首和尾加上部分代码,变成:
我们整理下这段代码:
恰好可以实现这个功能,不过还要注意一点,要将换行符替换成空格,防止解析成代码的时候报错,不过在这里为了方便理解原理,就只在代码里实现。
第一版
我们来尝试实现第一版:
为了验证是否有用:
HTML 文件:
JavaScript 文件:
完整的 Demo 可以查看 template 示例一
Function
在这里我们使用了 eval ,实际上 John Resig 在文章中使用的是 Function 构造函数。
Function 构造函数创建一个新的 Function 对象。 在 JavaScript 中, 每个函数实际上都是一个 Function 对象。
使用方法为:
arg1, arg2, ... argN 表示函数用到的参数,functionBody 表示一个含有包括函数定义的 JavaScript 语句的字符串。
举个例子:
那么 John Resig 到底是如何实现的呢?
第二版
使用 Function 构造函数:
使用方法依然跟第一版相同,具体 Demo 可以查看 template 示例二
不过值得注意的是:其实 tmpl 函数没有必要传入 data 参数,也没有必要在最后 return 的时候,传入 data 参数,即使你把这两个参数都去掉,代码还是可以正常执行的。
这是因为:
这里之所以依然传入了 data 参数,是为了下一版做准备。
with
现在有一个小问题,就是实际上我们传入的数据结构可能比较复杂,比如:
如果我们将这个数据结构传入 tmpl 函数中,在模板字符串中,如果要用到某个数据,总是需要使用
data.name
、data.friends
的形式来获取,麻烦就麻烦在我想直接使用 name、friends 等变量,而不是繁琐的使用data.
来获取。这又该如何实现的呢?答案是 with。
with 语句可以扩展一个语句的作用域链(scope chain)。当需要多次访问一个对象的时候,可以使用 with 做简化。比如:
最后:不建议使用 with 语句,因为它可能是混淆错误和兼容性问题的根源,除此之外,也会造成性能低下
第三版
使用 with ,我们再写一版代码:
具体 Demo 可以查看 template 示例三
第四版
如果我们的模板不变,数据却发生了变化,如果使用我们的之前写的 tmpl 函数,每次都会 new Function,这其实是没有必要的,如果我们能在使用 tmpl 的时候,返回一个函数,然后使用该函数,传入不同的数据,只根据数据不同渲染不同的 html 字符串,就可以避免这种无谓的损失。
具体 Demo 可以查看 template 示例四
下期预告
至此,我们已经跟着 jQuery 的作者 John Resig 实现了一个简单的模板引擎,虽然 underscore 基于这个思路实现,但是功能强大,相对的,代码也更加复杂一下,下一篇,我们一起去分析 underscore 的 template 函数实现。
underscore 系列
underscore 系列目录地址:https://github.com/mqyqingfeng/Blog。
underscore 系列预计写八篇左右,重点介绍 underscore 中的代码架构、链式调用、内部函数、模板引擎等内容,旨在帮助大家阅读源码,以及写出自己的 undercore。
如果有错误或者不严谨的地方,请务必给予指正,十分感谢。如果喜欢或者有所启发,欢迎 star,对作者也是一种鼓励。
The text was updated successfully, but these errors were encountered: