[关闭]
@lxjwlt 2015-11-08T19:00:27.000000Z 字数 3132 阅读 3729

字符串结合和ES6模板字符串

博文


ES6提供了一种新的字符串格式化的语法功能:模板字符串(template string),该语法允许字符串内嵌代码表达式。本文简要介绍其中的使用。

注:下面临时写的几个字符串结合函数只起到说明的作用,容错率低,不可用于实际开发,开发中应使用长期维护的代码库,比如ESJ模板引擎mustachejade...

传统的字符串结合

  1. var user = {
  2. name: 'lxjwlt',
  3. age23
  4. };
  5. user.name + ' who is in age ' + user.age + '.';
  6. // 结果:"lxjwlt who is in age 23."

项目开发中,这类代码很常见,但遇到更复杂的场景时,比如构建html,这类代码会变得难以书写,可读性差,而且维护难度大。

这时,我们可以使用字符串格式化函数来处理,简要例子:

  1. format('{0} who is in age {1}', user.name, user.age);
  2. // 结果:"lxjwlt who is in age 23."
  3. function format (template) {
  4. var reg = /\{(\d)\}/g,
  5. dataList = Array.prototype.slice.call(arguments, 1);
  6. return template.replace(reg, function (match, $1) {
  7. return dataList[$1];
  8. });
  9. }

这是最简单的字符串格式化,但是这种方式下,字符串中无法嵌入表达式,也就是说控制字符串生成的逻辑代码必须写到JS代码中。

所以再进一步,再复杂一点,我们希望模板内可以使用表达式,下面我们来实现一个最简单的模板引擎,只实现表达式和条件语句:

  1. var user = {
  2. name: 'lxjwlt',
  3. age: 23
  4. };
  5. template('%this.name% is a %if (this.age > 18) {% man %} else {% child %}%.', user);
  6. // 结果:"lxjwlt is a adult ."
  7. // 模板引擎
  8. function template (template, context) {
  9. var templateCode = templateToCode(template);
  10. return (new Function(templateCode)).apply(context);
  11. }
  12. // 模板转换为可执行代码
  13. function templateToCode (template, context) {
  14. var reg = /%([^%]+)%/g,
  15. conditionReg = /if \(.+\) \{|\} else \{|\}/,
  16. code = ['var str = "";'],
  17. lastIndex = 0,
  18. matchs;
  19. while (matchs = reg.exec(template)) {
  20. code.push(
  21. 'str = str + "' +
  22. template.slice(lastIndex, reg.lastIndex - matchs[0].length) +
  23. '";'
  24. );
  25. if (conditionReg.test(matchs[1])) {
  26. code.push(matchs[1]);
  27. } else {
  28. code.push('str = str + (' + matchs[1] + ');');
  29. }
  30. lastIndex = reg.lastIndex;
  31. }
  32. code.push('str = str + "' + template.slice(lastIndex) + '";');
  33. code.push('return str;');
  34. return code.join('');
  35. }

模板引擎使得模板与代码分离开来,同时,模板中也保留了逻辑处理。javascript框架中通常都会带有模板引擎功能。

上面列举了字符串三种方式,从字符串相加,到字符串格式化处理函数,再到模板引擎,三种方式各不同,使用场景也不一样,对应着不同的需求。那么,ES6引入的模板字符串语法实现了什么功能?能代替上述三种方式么?

模板字符串

首先,我们来看看最基本使用:

  1. var username = 'lxjwlt';
  2. `hi! ${username}.`; // "hi! lxjwlt."

注意!上面用的是反引号来包裹住字符串的,而不是单引号。反引号在键盘tab键的正上方。下面列出引号和反引号,我们可以仔细分辨一下其中的区别:

我们能发现,用反引号括住文本内容,文本内容中使用${}字面量插入逻辑表达式,这样就构成了一个模板字符串了。

ES6模板字符串的兼容性如下:

如果我们的chrome版本不太旧的话,现在完全可以打开控制台,我们马上来一发:

  1. `${1+1}`; // "2"

模板字符串预处理

有些情况下,我们需要对字符串中插入的值进行预处理,比如后台返回的值要进行htmlEncode处理,模板字符串支持使用函数来进行处理,该函数接收的参数形式如下:

strings, [value1, [value2, [value3 ...]]]

字符串会被${}分隔成一个个字符串片段保存在一个数组中,在函数的第一个参数中传入,对应上面的strings,而${}中表达式的返回值则从函数的其他参数中依次传入。我们现在可以实现“安全的”模板字符串了:

  1. var username = '<span>click me!</span>'
  2. safeTemplate`hi! ${username}.`;
  3. // 结果:"hi! &lt;span&gt;click me!&lt;/span&gt;"
  4. function safeTemplate (strings) {
  5. var str = [],
  6. values = Array.prototype.slice.call(arguments, 1),
  7. i;
  8. for (i = 0; i < strings.length; i++) {
  9. str.push(strings[i]);
  10. str.push(htmlEncode(values[i])); // 对插入值进行htmlEncode
  11. }
  12. return str.join('');
  13. }
  14. function htmlEncode () { /* ... */ }

字符串转换模板字符串

实际开发中,我们的模板可能会以字符串的形式从别的地方请求回来,这时候要把字符串转换为模板字符串,然而js中没有提供任何转换的方法。下面我们自己来实现一个:

  1. format("hi! ${name}", {name: "lxjwlt"}); // "hi! lxjwlt"
  2. function format (template, data) {
  3. var keys = Object.keys(data),
  4. dataList;
  5. dataList = keys.map(function (key) {
  6. return data[key]
  7. });
  8. // 这里使用反引号来构建模板引擎
  9. return new Function(keys.join(','), 'return `' + template + '`;')
  10. .apply(null, dataList);
  11. }

模板字符串的不足

更多阅读

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注