首发于我的博客 转载请注明出处

这是源于两年前,当我在做人生中第一个真正意义上的网站时遇到的一个问题

该网站采用前后端分离的方式,由后端的 REST 接口返回 JSON 数据,再由前端渲染到页面上。

同许多初学 Javascript 的菜鸟一样,起初,我也是采用拼接字符串的形式,将 JSON 数据嵌入 HTML 中。开始时代码量较少,暂时还可以接受。但当页面结构复杂起来后,其弱点开始变得无法忍受起来:

  • 书写不连贯。每写一个变量就要断一下,插入一个 +"。十分容易出错。

  • 无法重用。HTML 片段都是离散化的数据,难以对其中重复的部分进行提取。

  • 无法很好地利用 <template> 标签。这是 HTML5 中新增的一个标签,标准极力推荐将 HTML 模板放入 <template> 标签中,使代码更简洁。

当时我的心情就是这样的:

为了解决这个问题,我暂时放下了手上的项目,花了半个小时实现一个极简易的字符串模板。

需求描述

实现一个 render(template, context) 方法,将 template 中的占位符用 context 填充。要求:

  1. 不需要有控制流成分(如 循环、条件 等等),只要有变量替换功能即可

  2. 级联的变量也可以展开

  3. 被转义的的分隔符 {} 不应该被渲染,分隔符与变量之间允许有空白字符

例子:

render('My name is {name}', {name: 'hsfzxjy'
});  // My name is hsfzxjyrender('I am in {profile.location}', {name: 'hsfzxjy',profile: {location: 'Guangzhou'}
}); // I am in Guangzhourender('{ greeting }. \\{ This block will not be rendered }', {greeting: 'Hi'
}); // Hi. { This block will not be rendered }

实现

先写下函数的框架:

function render(template, context) {}

显然,要做的第一件事便是 匹配模板中的占位符

匹配占位符

匹配的事,肯定是交给正则表达式来完成。那么,这个正则表达式应该长什么样呢?

根据 需求 1、2 的描述,我们可以写出:

var reg = /\{([^\{\}]+)\}/g;

至于需求 3,我第一个想到的概念是 前向匹配,可惜 Javascript 并不支持,只好用一个折衷的办法:

var reg = /(\\)?\{([^\{\}\\]+)(\\)?\}/g;
// 若是第一个或第三个分组值不为空,则不渲染

现在,代码应该是这样:

function render(template, context) {var tokenReg = /(\\)?\{([^\{\}\\]+)(\\)?\}/g;return template.replace(tokenReg, function (word, slash1, token, slash2) {if (slash1 || slash2) {  // 匹配到转义字符return word.replace('\\', ''); // 如果 分隔符被转义,则不渲染}// ...})
}

占位符替换

嗯,正则表达式确定了,接下来要做的便是替换工作。

根据 需求2,模板引擎不仅要能渲染一级变量,更要渲染多级变量。这该怎么做呢?

其实很简单:将 token. 分隔开,逐级查找即可:

var variables = token.replace(/\s/g, '').split('.'); // 切割 token
var currentObject = context;
var i, length, variable;// 逐级查找 context
for (i = 0, length = variables.length, variable = variables[i]; i < length; ++i)currentObject = currentObject[variable];return currentObject;

不过,有可能 token 指定的变量并不存在,这时上面的代码便会报错。为了更好的体验,代码最好有一定的容错能力:

var variables = token.replace(/\s/g, '').split('.'); // 切割 token
var currentObject = context;
var i, length, variable;for (i = 0, length = variables.length; i < length; ++i) {variable = variables[i];currentObject = currentObject[variable];if (currentObject === undefined || currentObject === null) return ''; // 如果当前索引的对象不存在,则直接返回空字符串。
}return currentObject;

把所有的代码组合在一起,便得到了最终的版本:

function render(template, context) {var tokenReg = /(\\)?\{([^\{\}\\]+)(\\)?\}/g;return template.replace(tokenReg, function (word, slash1, token, slash2) {if (slash1 || slash2) {  return word.replace('\\', '');}var variables = token.replace(/\s/g, '').split('.');var currentObject = context;var i, length, variable;for (i = 0, length = variables.length; i < length; ++i) {variable = variables[i];currentObject = currentObject[variable];if (currentObject === undefined || currentObject === null) return '';}return currentObject;})
}

除去空白行,一共 17 行。

将函数挂到 String 的原型链

甚至,我们可以通过修改原型链,实现一些很酷的效果:

String.prototype.render = function (context) {return render(this, context);
};

之后,我们便可以这样调用啦:

"{greeting}! My name is { author.name }.".render({greeting: "Hi",author: {name: "hsfzxjy"}
});
// Hi! My name is hsfzxjy.

17 行代码实现的简易 Javascript 字符串模板相关推荐

  1. adsl拨号无公网地址如何用ddns_【好玩的网络-第5期】分享自编ddns程序,17行代码轻松实现免费ddns,服务器或nas玩家的福音...

    [好玩的网络]系列面向普通人的网络科普视频.我在我的哔哩哔哩账号(up主:旋律果子)更新[好玩的网络]视频版,在我的知乎(用户:曾彦)专栏更新[好玩的网络]文字版.最新消息以及预告在我的个人网站www ...

  2. Python仅用3行代码就能输出花式字符串图集,同事直呼666!

    Python用3行代码输出花式字符串图集,同事直呼666! 高逼格的日志 springboot 相信Java程序员看到上面的图,一定不会陌生.没错,springboot的启动日志.不知道其他人怎么想, ...

  3. 100行代码让您学会JavaScript原生的Proxy设计模式

    面向对象设计里的设计模式之Proxy(代理)模式,相信很多朋友已经很熟悉了. 其实和Java一样,JavaScript从语言层面来讲,也提供了对代理这个设计模式的原生支持.我们用一个不到100行代码的 ...

  4. 17行代码AC_51Nod - 2133 排队接水(贪心)

    励志用少的代码做高效表达 贪心算法模板题 贪心算法简单来讲即自顶向下,求解出每个子最优解,且每个子问题不会对下一个问题产生影响 题意:n个人排队接水,问如何排序才能使总等待时间最短,(正在接水的人和没 ...

  5. python模板代码替换_Python - 安全替换字符串模板(safe_substitute) 详细解释

    安全替换字符串模板(safe_substitute) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/27057339 字 ...

  6. 17行代码AC——L1-030 一帮一 (15分)(解题报告)

    立志用更少的代码做更高效的表达 "一帮一学习小组"是中小学中常见的学习组织方式,老师把学习成绩靠前的学生跟学习成绩靠后的学生排在一组.本题就请你编写程序帮助老师自动完成这个分配工作 ...

  7. python循环输出花式图案锁屏教程_Python仅用3行代码就能输出花式字符串图集,同事直呼666!...

    高逼格的日志 相信Java程序员看到上面的图,一定不会陌生.没错,springboot的启动日志.不知道其他人怎么想,我第一次看到这个启动日志的时候,就觉得好炫酷.然而,大家在日常的Python开发中 ...

  8. 24行代码-Leecode 2063. 所有子字符串中的元音——Leecode周赛系列

    题目链接:https://leetcode-cn.com/problems/vowels-of-all-substrings/ 题解汇总:https://zhanglong.blog.csdn.net ...

  9. 1041 考试座位号 (15分)——17行代码AC

    立志用更少的代码做更高效的表达 Pat乙级最优化代码+题解+分析汇总-->传送门 每个 PAT 考生在参加考试时都会被分配两个座位号,一个是试机座位,一个是考试座位.正常情况下,考生在入场时先得 ...

最新文章

  1. Python3--批量爬取数据之调用有道api进行翻译
  2. JMeter入门,测试计划编写(http请求)
  3. C语言入夏标志,青岛真的入夏了吗?青岛20°C的梗是什么?
  4. 车牌识别EasyPR(5)——文字定位
  5. 关于Redis命令keys在性能方面的说明
  6. 加密Python脚本
  7. Mac安装wget的两种方法
  8. JAVA获取本机IP地址
  9. python 画图 线标注_Python中画图时候的线类型
  10. linux双显卡配置_linux下的双显卡切换
  11. qq邮箱对方服务器退回,为什么我用QQ邮箱发邮件被退回来了?他说地 – 手机爱问...
  12. 跨境电子商务( Cross-Border Electronic Commerce )是什么?
  13. SQL常用的一些关键字
  14. 翻译考试用计算机作答,上半年CATTI考试方式还是纸笔,下半年就实行全面机考?真是几家欢喜几家愁!...
  15. 单条视频播放3700w+,生鲜产品如何开启变现之路?
  16. 静态网页和动态网页的区别
  17. 我的成长记1:手把手教你如何画出令人称赞的图(程序员必读)
  18. Py之lulu:lulu库的简介、安装、案例应用之详细攻略
  19. 读《哥德尔、艾舍尔、巴赫——集异壁之大成》
  20. [数据分析实例5]使用python-pandas对历届世界杯数据进行数据分析,并用matplotlib绘图,干货满满,赶紧收藏学习起来!

热门文章

  1. 前端入门-day2(常见css问题及解答)
  2. modbus_tk与Modubs Slave结合使用
  3. 重塑营销场景,用友优普助宁波力劲销售管理精细化
  4. 64位x86的函数调用栈布局
  5. 【312天】我爱刷题系列071(2017.12.14)
  6. 基于表格存储的高性能监控数据存储计算方案
  7. pythonm 用法-------list实现购物车
  8. Oracle把Java EE的未来押在Rest API上了?
  9. C# 判断上传图片是否被PS修改过的方法
  10. 配置VSS2005(在局域网内搭建服务器)