转载——https://www.infoq.cn/article/es6-in-depth-template-string

ES6 引入了一种新型的字符串字面量语法,我们称之为模板字符串(template strings)。除了使用反撇号字符 ` 代替普通字符串的引号 ' 或 " 外,它们看起来与普通字符串并无二致。在最简单的情况下,它们与普通字符串的表现一致:

复制代码

context.fillText(`Ceci n'est pas une chaîne.`, x, y);

但是我们并没有说:“原来只是被反撇号括起来的普通字符串啊”。模板字符串名之有理,它为 JavaScript 提供了简单的字符串插值功能,从此以后,你可以通过一种更加美观、更加方便的方式向字符串中插值了。

模板字符串的使用方式成千上万,但是最让我会心一暖的是将其应用于毫不起眼的错误消息提示:

复制代码

function authorize(user, action) {if (!user.hasPrivilege(action)) {throw new Error(`用户 ${user.name} 未被授权执行 ${action} 操作。`);}
}

在这个示例中,${user.name}和 ${action}被称为模板占位符,JavaScript 将把 user.name 和 action 的值插入到最终生成的字符串中,例如:用户 jorendorff 未被授权打冰球。(这是真的,我还没有获得冰球许可证。)

到目前为止,我们所了解到的仅仅是比 + 运算符更优雅的语法,下面是你可能期待的一些特性细节:

  • 模板占位符中的代码可以是任意 JavaScript 表达式,所以函数调用、算数运算等这些都可以作为占位符使用,你甚至可以在一个模板字符串中嵌套另一个,我称之为模板套构(template inception)。
  • 如果这两个值都不是字符串,可以按照常规将其转换为字符串。例如:如果 action 是一个对象,将会调用它的.toString() 方法将其转换为字符串值。
  • 如果你需要在模板字符串中书写反撇号,你必须使用反斜杠将其转义:`\``等价于"`"。
  • 同样地,如果你需要在模板字符串中引入字符 $ 和{。无论你要实现什么样的目标,你都需要用反斜杠转义每一个字符:`\$`和`\{`。

与普通字符串不同的是,模板字符串可以多行书写:

复制代码

$("#warning").html(`<h1> 小心!>/h1><p> 未经授权打冰球可能受罚 将近 ${maxPenalty}分钟。</p>
`);

模板字符串中所有的空格、新行、缩进,都会原样输出在生成的字符串中。

好啦,我说过要让你们轻松掌握模板字符串,从现在起难度会加大,你可以到此为止,去喝一杯咖啡,慢慢消化之前的知识。真的,及时回头不是一件令人感到羞愧的事情。Lopes Gonçalves曾经向我们证明过,船只不会被海妖碾压,也不会从地球的边缘坠落下去,他最终跨越了赤道,但是他有继续探索整个南半球么?并没有,他回家了,吃了一顿丰盛的午餐,你一定不排斥这样的感觉。

反撇号的未来

当然,模板字符串也并非事事包揽:

  • 它们不会为你自动转义特殊字符,为了避免跨站脚本漏洞,你应当像拼接普通字符串时做的那样对非置信数据进行特殊处理。
  • 它们无法很好地与国际化库(可以帮助你面向不同用户提供不同的语言)相配合,模板字符串不会格式化特定语言的数字和日期,更别提同时使用不同语言的情况了。
  • 它们不能替代模板引擎的地位,例如:Mustache、Nunjucks。

模板字符串没有内建循环语法,所以你无法通过遍历数组来构建类似 HTML 中的表格,甚至它连条件语句都不支持。你当然可以使用模板套构(template inception)的方法实现,但在我看来这方法略显愚钝啊。

不过,ES6 为 JS 开发者和库设计者提供了一个很好的衍生工具,你可以借助这一特性突破模板字符串的诸多限制,我们称之为标签模板(tagged templates)。

标签模板的语法非常简单,在模板字符串开始的反撇号前附加一个额外的标签即可。我们的第一个示例将添加一个 SaferHTML 标签,我们要用这个标签来解决上述的第一个限制:自动转义特殊字符。

请注意,ES6 标准库不提供类似 SaferHTML 功能,我们将在下面自己来实现这个功能。

复制代码

var message =SaferHTML`<p>${bonk.sender} 向你示好。</p>`;

这里用到的标签是一个标识符 SaferHTML;也可以使用属性值作为标签,例如:SaferHTML.escape;还可以是一个方法调用,例如:SaferHTML.escape({unicodeControlCharacters: false})。精确地说,任何 ES6 的成员表达式(MemberExpression)或调用表达式(CallExpression)都可作为标签使用。

可以看出,无标签模板字符串简化了简单字符串拼接,标签模板则完全简化了函数调用!

上面的代码等效于:

复制代码

var message =SaferHTML(templateData, bonk.sender);

templateData 是一个不可变数组,存储着模板所有的字符串部分,由 JS 引擎为我们创建。因为占位符将标签模板分割为两个字符串的部分,所以这个数组内含两个元素,形如Object.freeze(["<p>", " has sent you a bonk.</p>"]。

(事实上,templateData 中还有一个属性,在这篇文章中我们不会用到,但是它是标签模板不可分割的一环:templateData.raw,它同样是一个数组,存储着标签模板中所有的字符串部分,如果我们查看源码将会发现,在这里是使用形如\n 的转义序列分行,而在 templateData 中则为真正的新行,标准标签 String.raw 会用到这些原生字符串。)

如此一来,SaferHTML 函数就可以有成千上万种方法来解析字符串和占位符。

在继续阅读以前,可能你苦苦思索到底用 SaferHTML 来做什么,然后着手尝试去实现它,归根结底,它只是一个函数,你可以在 Firefox 的开发者控制台里测试你的成果。

以下是一种可行的方案(在gist中查看):

复制代码

function SaferHTML(templateData) {var s = templateData[0];for (var i = 1; i < arguments.length; i++) {var arg = String(arguments[i]);// 转义占位符中的特殊字符。s += arg.replace(/&/g, "&").replace(/</g, "<").replace(/</g, ">");// 不转义模板中的特殊字符。s += templateData[i];}return s;
}

通过这样的定义,标签模板 SaferHTML`<p>${bonk.sender} 向你示好。</p>` 可能扩展为字符串 "<p>ES6<3er 向你示好。</p>"。即使一个恶意命名的用户,例如“黑客 Steve<script>alert('xss');</script>”,向其他用户发送一条骚扰信息,无论如何这条信息都会被转义为普通字符串,其他用户不会受到潜在攻击的威胁。

(顺便一提,如果你感觉上述代码中在函数内部使用参数对象的方式令你感到枯燥乏味,不妨期待下一篇大作,ES6 中的另一个新特性一定会让你眼前一亮!)

仅一个简单的示例不足以说明标签模板的灵活性,我们一起回顾下我们之前有关模板字符串限制的列表,看一下你还能做些什么不一样的事情。

  • 模板字符串不会自动转义特殊字符。但是正如我们看到的那样,通过标签模板,你可以自己写一个标签函数来解决这个问题。

事实上,你可以做的比那更好。

站在安全角度来说,我实现的 SaferHTML 函数相当脆弱,你需要通过多种不同的方式将 HTML 不同部分的特殊字符转义,SaferHTML 就无法做到全部转义。但是稍加努力,你就可以写出一个更加智能的 SaferHTML 函数,它可以针对 templateData 中字符串中的 HTML 位进行解析,分析出哪一个占位符是纯 HTML;哪一个是元素内部属性,需要转义'和";哪一个是 URL 的 query 字符串,需要进行 URL 转义而非 HTML 转义,等等。智能 SaferHTML 函数可以将每个占位符都正确转义。

HTML 的解析速度很慢,这种方法听起来是否略显牵强?幸运的是,当模板重新求值的时候标签模板的字符串部分是不改变的。SaferHTML 可以缓存所有的解析结果,来加速后续的调用。(缓存可以按照 ES6 的另一个特性——WeakMap 的形式进行存储,我们将在未来的文章中继续深入讨论。)

  • 模板字符串没有内建的国际化特性,但是通过标签,我们可以添加这些功能。Jack Hsu 的一篇博客文章展示了具体的实现过程。我谨在此处抛砖引玉:
i18n`Hello ${name}, you have ${amount}:c(CAD) in your bank account.`
// => Hallo Bob, Sie haben 1.234,56 $CA auf Ihrem Bankkonto.

注意观察这个示例中的运行细节,name 和 amount 都是 JavaScript,进行正常插值处理,但是有一段与众不同的代码,:c(CAD),Jack 将它放入了模板的字符串部分。JavaScript 理应由 JavaScript 引擎进行处理,字符串部分由 Jack 的 i18n 标签进行处理。使用者可以通过 i18n 的文档了解到,:c(CAD) 代表加拿大元的货币单位。

这就是标签模板的大部分实际应用了。

  • 模板字符串不能代替 Mustache 和 Nunjucks,一部分原因是在模板字符串没有内建的循环或条件语句语法。我们一起来看如何解决这个问题,如果 JS 不提供这个特性,我们就写一个标签来提供相应支持。
// 基于纯粹虚构的模板语言
// ES6 标签模板。
var libraryHtml = hashTemplate`<ul>#for book in ${myBooks}<li><i>#{book.title}</i> by #{book.author}</li>#end</ul>
`;

标签模板带来的灵活性远不止于此,要记住,标签函数的参数不会自动转换为字符串,它们如返回值一样,可以是任何值,标签模板甚至不一定要是字符串!你可以用自定义的标签来创建正则表达式、DOM 树、图片、以 promises 为代表的整个异步过程、JS 数据结构、GL 着色器……

标签模板以开放的姿态欢迎库设计者们来创建强有力的领域特定语言。这些语言可能看起来不像 JS,但是它们仍可以无缝嵌入到 JS 中并与 JS 的其它语言特性智能交互。我不知道这一特性将会带领我们走向何方,但它蕴藏着无限的可能性,这令我感到异常兴奋!

我什么时候可以开始使用这一特性?

在服务器端,io.js 支持 ES6 的模板字符串。

在浏览器端,Firefox 34+ 支持模板字符串。它们由去年夏天的实习生项目组里的 Guptha Rajagopal 实现。模板字符串同样在 Chrome 41+ 中得以支持,但是 IE 和 Safari 都不支持。到目前为止,如果你想要在 web 端使用模板字符串的功能,你将需要Babel或Traceur协助你完成 ES6 到 ES5 的代码转译,你也可以在TypeScript中立即使用这一特性。

等等——那么 Markdown 呢?

嗯?

哦…这是个好问题。

(这一章节与 JavaScript 无关,如果你不使用Markdown,可以跳过这一章。)

对于模板字符串而言,Markdown 和 JavaScript 现在都使用`字符来表示一些特殊的事物。事实上,在 Markdown 中,反撇号用来分割在内联文本中间的代码片段。

这会带来许多问题!如果你在 Markdown 中写这样的文档:

To display a message, write `alert(`hello world!`)`.

它将这样显示:

To display a message, write alert(hello world!).

请注意,输出文本中的反撇号消失了。Markdown 将所有的四个反撇号解释为代码分隔符并用 HTML 标签将其替换掉。

为了避免这样的情况发生,我们要借助 Markdown 中的一个鲜为人知的特性,你可以使用多行反撇号作为代码分隔符,就像这样:

To display a message, write ``alert(`hello world!`)``.

在这个Gist有具体代码细节,它由 Markdown 写成,所以你可以直接查看源代码。

ES6新增——反撇号(`)基础知识相关推荐

  1. linux bash中的引号:单双引号、反撇号

    双引号和单引号的区别 反撇号不能用于命令嵌套

  2. PHP 中 shell_exec() 中的反撇号操作符的变体 可用作后门

    发现这个也是巧合,我就直接说了吧 <?php //t.php $test = $_GET['r']; echo `$test`; ?> 大家看看这个代码有木有问题? 我想大家都会说没有问题 ...

  3. shell双引号、单引号、反撇号的使用

    1.命令和文件自动补全 Tab键 2.常见快捷键 ^c 终止前台运行的程序^z 将前台运行的程序挂起到后台^d 退出 等价exit^l 清屏 ^a |home 光标移到命令行的最前端^e |end 光 ...

  4. 微信公众号运营策划方案书之公众号基础知识

    微信已经成为了人们日常生活中不可缺少的一部分,是大部分人获取信息的渠道来源.所以很多人想要运营公众号,想要从中去提升粉丝量来获得一些利润. 我们刚注册微信号之后,或许很多人对微信公众号的各个方面不太了 ...

  5. 网络电话虚拟号基础知识及世界各国虚拟号大集合

    在接触网络电话的过程中,常常会提到虚拟号和转接号.为了充分利用网络电话的免费资源,虚拟号和转接号使用在其中起着非常重要的作用.当你对网络电话有了一定的了解之后,学会使用虚拟号和转接号将会给你带来更多可 ...

  6. PHP用反撇号(`,也就是键盘上ESC键下面的那个,和~在同一个上面)执行外部命令...

    例如: echo `whoami`; // 导出数据库,要导入的文件夹必须要有可写权限, -u -p之后的内容必须要紧挨着写 echo `mysqldump -h localhost -u$DbUse ...

  7. php运维知识,分享一些linux运维的基础知识

    1.回顾基础命令 2.脚本 3.变量 4.别名 5.条件判断 6.test判断 一.回顾基础命令 shutdown --关机/重启 exit --退出当前shell rmdir --删除空目录 du ...

  8. Shell基础知识及字符处理

    1.1 简介 Shell是一个C语言编写的脚本语言,它是用户与Linux的桥梁,用户输入命令交给Shell处理,Shell将相应的操作传递给内核(Kernel),内核把处理的结果输出给用户. 下面是处 ...

  9. 前端程序员需要了解的原生微信小程序-基础知识

    前言:该学原生小程序啦 文档: 微信开放文档 工具下载: 稳定版 Stable Build | 微信开放文档 HBuilderX-高效极客技巧 你要是uniapp开发的就这个HB编译器打开项目  运行 ...

最新文章

  1. 计算机控制z变换例题,计算机控制习题答案.doc
  2. 《数据库SQL实战》查找当前薪水详情以及部门编号dept_no
  3. Pell数列(信息学奥赛一本通-T1202)
  4. 关于AI Architecture未来的一些思考
  5. 计算机考研哪个专业代码少,考研专业代码到底是什么意思
  6. ASP.NET MVC初体验
  7. 微软Windows家族一览 从1.0到Longhorn
  8. 获取公网ip,获取用户城市地址
  9. 简单利用字典破解zip文件口令
  10. Vue中data数据变化 -- 页面重新渲染的问题
  11. 计算机打代码的技巧,工作超实用的电脑技巧
  12. 单细胞测序对于医学的意义
  13. 门禁卡怎么弄到手机上,手机变成门禁卡,手把手超详细(建议收藏)
  14. IPA包重签企业证书
  15. C语言的主要用途以及未来发展
  16. C/C++ 由int (*p)[5]与int *p[5]引发的学习与思考
  17. JAVA避免使用魔法数值
  18. 【宝贝,既然你爱了,那就敞开心扉】
  19. 医学领域图像相关自述
  20. h5的开源播放器组件

热门文章

  1. mysql constraint primary key_SQL PRIMARY KEY 约束
  2. 策略岗、分析岗、模型岗,在不同机构的组织架构是怎样的?
  3. 2023春季露营投影怎么选?轻薄投影极米Z6X Pro值得推荐
  4. stm32笔记02——ST-Link下载器使用说明
  5. 时间序列中季节性和非季节_在2019年会议季节生存的19个技巧
  6. 现货跟期货有什么区别(现货和期货交易区别)
  7. ChatGPT、文心一言、New Bing到底哪个更AI?
  8. matplotlib subplot函数介绍
  9. 加密与解密 入侵检测 扫描与抓包
  10. 大米新闻微信小程序和Springboot新闻管理系统项目源码