阅读更多

1顶
0踩

Web前端
ES6作为新一代JavaScript标准,即将与广大前端开发者见面。为了让大家对ES6的诸多新特性有更深入的了解,Mozilla Web开发者博客推出了《ES6 In Depth》系列文章。CSDN已获授权,将持续对该系列进行翻译,供大家学习借鉴。本文为该系列的第四篇。

前两次学习了生成器和迭代器以后,脑袋有没有一团浆糊?哈哈。我承诺过本次我们将学习一些简单的东西。

那我们现在就开始吧!

“小句号”的基本使用

ES6新引入了一种新的字符串语法——模版字符串(Template Strings),它看起来和普通的字符串很像,区别在于它不是由单引号'或者双引号"来闭合,而是使用`(俗称:小句号)。我们来看个最简单的例子,它们其实就是字符串而已:
context.fillText(`Ceci n'est pas une chaîne.`, x, y);  

但是既然它被叫做“模版字符串”,那它应该不仅仅是用小句号来闭合的普通字符串吧?模版字符串让JavaScript有了一个简单的字符串插值功能——既写法美观又能很方便地将JavaScript变量替换到字符串中。

很多情景下都可以用到它,但最打动我的是它在毫不起眼的错误消息中的使用:
function authorize(user, action) {
  if (!user.hasPrivilege(action)) {
    throw new Error(
      `User ${user.name} is not authorized to do ${action}.`);
  }
}

在这个例子中,${user.name}和${action}被称作模版替换位。在生成的字符串中,JavaScript会用使用user.name和action的变量值来替换字符串的模版替换位。最后生成的字符串为:User jorendorff is not authorized to do hockey(你可以自己试试,我可没忽悠你)。

目前为止,它只是个比+(加号连接符)在语法上略微美观一些而已,你可能想了解更多关于它的细节:
  • 模版替换位中的代码可以是任何JavaScript的表达式,比如函数调用、算数运算等等都是允许的(只要你乐意,你甚至可以在模版字符串中嵌套模版字符串,有种模版中的《盗梦空间》的感觉)。
  • 如果插入的值不是字符串,它将被转换为字符串。例如,如果action是个对象,它的.toString()方法将会被调用。
  • 如果你的模版字符串中包含 ` (小句号),需要使用转义字符`\``,效果相当于 "`"。
  • 举一反三,如果你的模版字符串中需要 ${ 这两个字符,我不想去关心你为什么要这么写,但是你可以使用转义其中任意一个字符:`write \${  或者 $\{`。

与普通字符串不同的是,模版字符串可以写成多行:
$("#warning").html(`
  <h1>Watch out!</h1>
  <p>Unauthorized hockeying can result in penalties
  of up to ${maxPenalty} minutes.</p>
`);

在模版字符串中,所有空格、换行、缩进都是逐字输出的。

好的,就像我上篇文章所承诺的,我觉得我必须对你大脑的健康负责。所以给一个小小的警告:接下来的内容就比较费脑一点了。你可以现在就放弃阅读,喝杯咖啡享受一下,放松一下大脑。认真地说,不用为放弃下面的内容而感到羞愧噢。 当Lopes Gonçalves穿过了赤道,证明了不会被可怕的海怪吃掉或掉进地球的尽头,然后他还需要去航行整个完整的南半球来增加论证吗?不需要!他返航了,回到家吃了顿美美的午餐。换做是你也会这么做,对不对?
深入讨论“小句号”

我们来讨论一些模版字符串的局限性。
  • 它不会为你自动转义关键字。为了防止脚本注入,你需要认真小心对待那些不受信任的数据,就像你曾经小心地拼接字符串一样。
  • 它并没有明确地说明如何配合国际化库(一个针对用户所处的国家/语言不同来国际化你的代码的库)来使用。模版字符串不会处理特定语言的数字、日期等的格式化。
  • 它并不能代替像MustacheNunjucks这样的模板库。
  • 模版字符串没有内置针对循环的语法——通过数组来循环生成一个HTML表格;甚至条件语句也不支持。(当然,你可以使用模版嵌套来实现,但是这样的方法太笨拙,我认为不可取。)

ES6在模版字符串中为JS开发者和库设计人员提供了一种解决方案来帮助他们处理这些局限性问题。这个特性被称做模版标记。

模版标记的语法很简单。我们只需要在“小句号”的前面加一个额外的标记。在我们接下来的第一个例子中,SaferHTML就是它的标记,我们使用这个标记来处理上面列表中的第一个局限性问题:自动转义关键字。

必须清楚SaferHTML并不是ES6标准库中的内容。在下面我们将会自己来实现它。
var message =
  SaferHTML`<p>${bonk.sender} has sent you a bonk.</p>`;

这里使用了一个标识符SaferHTML来作为标记,标记也可以是一个属性——SaferHTML.escape,甚至可以是一个函数调用——SaferHTML.escape({unicodeControlCharacters: false})。(说明一下,任何ES6的MemberExpressio类或CallExpression类都可以作为标记使用)。

可以看出不含标记的模版字符串适用于简单的字符串拼接。标记模版完全适用于其它场景:如函数调用。

上面的代码与这段等效:
var message =
  SaferHTML(templateData, bonk.sender);

templateData 是由模版的字符串部分所组成的不可变数组,由JS引擎为我们提供。下面是一个拥有两个元素的数组,因为在标记模板中他们被模版替换所分割,有两个字符串部分。所以templateData 应该是这个样子的:Object.freeze(["<p>", " has sent you a bonk.</p>"]。

(实际上templateData 还有一个属性。我并不打算在这篇文章中用到它,为了完整性我还是提一下: templateData.raw 是另一个囊括了标记模版中所有字符串部分的数组,它的源码就和它的名称(raw)一样原始——还保留着\n这样的转义序列,而不是被转到新的一行等。标准的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]);

    // Escape special characters in the substitution.
    s += arg.replace(/&/g, "&")
            .replace(/</g, "<")
            .replace(/>/g, ">");

    // Don't escape special characters in the template.
    s += templateData[i];
  }
  return s;
}

定义了这个方法以后,SaferHTML`<p>${bonk.sender} has sent you a bonk.</p>`将会被解析为 "<p>ES6&lt;3er has sent you a bonk.</p>"。那么你的用户传入的值都是安全的,即使有人恶意地将bonk.sender 赋值为 "Hacker Steve <script>alert('xss');</script>",返回的也是不可执行的字符串,无论这段字符串的含义是什么,都不会有安全漏洞。

(顺便说一句,如果你觉得函数使用参数对象的方式让你感觉这样很笨重,我们下次将换用另一种方法。ES6还有另一个我认为你会喜欢的新特性。)

一个例子并不能说明标记模版的灵活性。让我们再来看看我们能为之前列出的那些模版字符串的局限性做些什么改进。
  • 模版字符串不自动转义特殊字符。但是我们已经看到了,使用标记模版我们就能解决这个问题。实际上,我们能做得更好。

从安全性的角度来看,我的SaferHTML函数功能性非常弱。HTML中不同的地方有不同的关键字需要不同的转义方式。SaferHTML把它们全部都转义,但是我们可以再付出一些努力把SaferHTML写的更精明一点,完全按照字节来解析templateData中的字符串,这样我们就知道哪些替换位是在纯HTML中;哪些是在元素属性中,这些 ‘ 和 “ 就需要转义;那些在URL查询字符串中需要使用URL转义而不是HTML转义等等。它可以准确地对每个替代位进行正确的转义。

也许你会有疑问——HTML解析效率低,这方法是不是很牵强?幸运的是标记模版的字符串部分是固定不变的。SaferHTML可以将这部分的解析结果缓存起来,这样就可以提高运行速度了。(这个缓存可以是一个WeakMap,WeakMap是ES6的新特性,我们在以后的文章中将会对它有所讨论。)
  • 模版字符串没有涉及国际化相关的特性。好在有了标记,这个问题就迎刃而解。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)表示加拿大元,那么amount则表示了加拿大元的数额。

这就是标记模板的作用了。
  • 它并不能代替像Mustache 、Nunjucks这样的模板库,大部分原因是因为它没有内置对循环和条件句的支持。那么现在我们一起来看看如何解决这个问题,准备好了吗?

如果JS没有为我们提供某个特性,那我们就自己写一个!
// Purely hypothetical template language based on
// ES6 tagged templates.
var libraryHtml = hashTemplate`
  <ul>
    #for book in ${myBooks}
      <li><i>#{book.title}</i> by #{book.author}</li>
    #end
  </ul>
`;

它的灵活性还不止于此。记住,标记函数的参数不会自动转换为字符串。它的返回值也是这样,它们可以是任何类型,标记模版不一定是字符串!你可以使用自定义标签来创建自定义正则表达式、DOM树、图片、完整的异步流程、JS数据结构、GL着色器等等。

标记模版鼓励库开发人员去创建强大的基于特定领域的语言。这些语言看起来一点也不像JS,但是他们可以无缝地嵌入JS中并且可以智能地与其它语言进行交互。现在,我想不出其它任何有类似特性的语言,我不知道这个特性将来会给我们的开发带来什么改变,但这个改变应该是令人惊喜的。

我什么时候可以开始使用模版字符串?

在服务端,io.js已经开始支持模版字符串了。

浏览器里,FireFox 34+已经支持模版字符串。去年夏天Guptha Rajagopal已经把它作为一个实习项目。Chrome 41+也支持模板字符串,IE和Safari不支持。现在,如果你想在web项目中使用模版字符串你需要用到Babel或Traceur来支持;你也可以在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写的,你可以查看源码。

下期预告

下篇文章,我们将学习两个新特性,在其它语言中这两个特性已经被程序员们愉快地使用了几十年了:其中一个是为了那些喜欢尽量避免使用参数的开发人员准备的,另一个是给那些喜欢使用很多参数的人准备的。当然,两种特性都为我们提供了,我们可以根据个人对函数的使用习惯来选择。

这些特性可以直接在Firefox中测试,所以下次我们一起来试一下吧,我们的客座来宾Benjamin Peterson将为大家讲解ES6的default parameters和rest parameters。(译者:向渝 责编:陈秋歌)

原文链接:ES6 In Depth: Template strings

本译文遵循Creative Commons Attribution Share-Alike License v3.0
1
0
评论 共 1 条 请登录后发表评论
1 楼 white_crucifix 2015-07-01 14:33
新的js特性其实放出了一个信号:js不再是一种页面附带的小工具,而是构建一个应用的编程语言。

有没有发现,${}符号,很熟悉,这不是jsp上的el表达式么。如果作为页面小工具的js像往常一样,写在jsp文件里,那么这个符号就会被java处理掉,而且会报错

所以,JS,就是要写在JS文件里

比如angularjs,比如reactjs,甚至extjs,等等

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • Struts2入门教程(全新完整版)

    1.解压struts-2.1.6-all.zip 3 2.六个基本包 3 3.初识struts2配置文件 4 (1).web.xml文件 4 (2).struts.xml文件 4 (3).struts.properties(参default.properties) 4 (4)struts-default.xml 4 (5)其它...

  • struts2.1.6教程二、struts.xml配置及例程

    在struts2中一些配置(比如常量)可以同时在struts-default.xml(只读性),strtus-plguin.xml(只读性),struts.xml,struts.properties和web.xml文件中配置,它们的优先级逐步升高,即是说后面的配置会覆盖掉前面...

  • Struts(23)校验器

    手动输入完成校验 1.普通的处理方式:只需要在action中重写validate()方法 2.一个action对应多个逻辑处理方法:指定校验摸个特定方法的方式: 重写validateXxxx()方法。Eg:如果,只校验login方法,则只需重写...

  • struts2问题小结

    struts2.1.6已不用s:datetimepicker标签,要想使用,需导入struts2-dojo-plugin-2.1.6.jar, 在页面导入 标签, 中加入 就能使用了 我测试了一把还是有些问题从九月份到十二月份的显示还 有些问题 如下图所示...

  • struts2表单验证问题

     org.apache.struts2.validators.DWRValidator在 struts2-dwr-plugin-2.1.6.jar中,需要导入。 2.web.xml: xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=...

  • struts2 基本流程与配置

    struts2框架 什么是框架,框架有什么用? 框架 是 实现部分功能的代码 (半成品),使用框架简化企业级软件开发 ,提高开发效率。学习框架 ,清楚的知道框架能做什么? 还有哪些工作需要自己编码实现 ? ...

  • Java框架学习之Struts2

    整合Ajax支持 (2)struts2目录结构: apps:该文件夹包含了基于struts2 的示例应用,这些示例应用对于学习者是非常有用的 docs:该文件夹下包含了struts2 相关文档,包括struts2 快速入门、struts2的文档以及API文档等 ...

  • struts2的一点理解

    当action设置了某个属性值后,struts2会把这些属性值封装到一个叫struts.valueStack的请求属性里面。 我们可以通过ValueStack vs = request.getAttribute("struts.valueStack");获取输出的全部信息 vs.findValue(...

  • Struts2 验证框架

    但自己用的是 Struts2.1.6 所以在学的时候和书上有很多的出入.自己英语水平还不到能顺利看懂 英文文档的水平. 有些问题得不到解决.网上找了一下,也没有什么收获.郁闷!Struts2.1 在 Ajax 方面比 Struts2.0 改动了...

  • Struts2.1.x、Hibernate3.5.X实战总结

     刚开始用struts2.1.8、Hibernate3.5.3,不断地遇到问题、解决问题。学新东西还是让人痛并快乐着。  把一些东西记录下来,希望对其它朋友有所帮助。 [color=darkred][b](一)validateXxx返回不同的input页面[/b...

  • Struts2 struts2基本流程与配置

    struts2框架 什么是框架,框架有什么用? 框架 是 实现部分功能的代码 (半成品),使用框架简化企业级软件开发 ,提高开发效率。 学习框架 ,清楚的知道框架能做什么? 还有哪些工作需要自己编码实现 ...

  • struts2学习笔记

    更强大、更易用输入校验功能 整合 Ajax 支持 等等 Struts2 的组成 :   struts2 目录结构 : apps: 该文件夹包含了基于 struts2 的示例应用,这些示例应用对于学习者是非常有用的 docs: 该...

  • Struts2学习第一天——struts2基本流程与配置

    struts2框架 struts2快速入门 Struts2 处理流程 模仿struts2流程完成入门程序 struts2的流程分析以及工具配置 struts2配置(重点) 1.struts2配置文件加载顺序 2.关于Action的配置 关于常量配置 Action 关于Action类的...

  • struts2 jar

    struts2 核心包struts2-core-2.1.8.1struts2的核心jar包,不可缺少的 xwork-core-2.1.6xwork的核心包,由于Struts2是由xwork的延伸 有些类依然关联着 xwork的类 aopalliance-1.0这个包为AOP提供了最普通和通用的接口...

  • Struts2---第一篇

    Struts2 什么是框架,有什么用处: 框架 是实现部分功能的代码(半成品),使用框架简化企业级软件开发,提高开发效率 学习框架,清楚的知道框架可以做什么,还有哪些工作需要自己实现? Struts 2是什么...

  • Struts2框架学习

    Struts框架学习了解Struts2如何更好的理解Struts2框架为什么使用Struts2控制器学习Struts2框架Struts的优点搭建Struts2开发环境1、导入Struts2所需要的jar包2、定义struts.xml文件3、在web.xml文件中对struts2框架的...

  • 杰神之struts框架

    struts2框架 什么是struts2框架,它有什么用? Struts 2是在 struts 1和WebWork的技术基础上进行了合并的全新的Struts 2框架。 其全新的Struts 2的体系结构与Struts 1的体系结构差别巨大。Struts 2以WebWork为核心...

  • JAVAWEB开发之Struts2详解(一)——Struts2框架介绍与快速入门、流程分析与工具配置以及Struts2的配置以及Action和Result的详细使用

    Struts2框架介绍 Struts2开发入门 Struts2开发入门示例 模仿Struts2流程完成入门程序 Struts2流程分析与工具配置 Struts2处理流程 关于手动配置strutsxml文件中提示操作 关联strutsxml源文件 Config Brower插件使用 ...

  • Struts2-01没有成功:请求转发到另一个Action和请求转发jsp

    struts2目录结构: apps:该文件夹包含了基于struts2 的示例应用,这些示例应用对于学习者是非常有用的 docs:该文件夹下包含了struts2 相关文档,包括struts2 快速入门、struts2的文档以及API文档等 lib:该文件夹下...

  • HTML中的数据绑定(Data Binding)

    有没想过在javascript中使用recordset?原来在客户端操作数据也可以这样简单,定义一个数据源,将数据绑定在各种tag上,实现应用程序般的效果,酷毙了!(首先申明一点,文章的内容全部来自msdn,不过用我自己的话总结而已。)先看看这样两个例子:http://msdn.microsoft.com/workshop/samples/author/databind/dbevts.htmhtt

Global site tag (gtag.js) - Google Analytics