❤ ES6-4【字符串的扩展】

149 阅读3分钟

❤ ES6-4【字符串的扩展】

4、字符串的扩展

1、字符的 Unicode 表示法

2、字符串的遍历器接口

3、直接输入 U+2028 和 U+2029

4、JSON.stringify() 的改造

5、模板字符串

6、实例:模板编译

7、标签模板

8、模板字符串的限制

1、字符的 Unicode 表示法

ES6 加强了对 Unicode 的支持,允许采用\uxxxx形式表示一个字符,其中xxxx表示字符的 Unicode 码点,但是,这种表示法只限于码点在\u0000~\uFFFF之间的字符。超出这个范围的字符,必须用两个双字节的形式表示。

观察发现: u四个零到u四个F之间

"\uD842\uDFB7" // "𠮷"

"\u20BB7" // " 7" 上面代码表示,如果直接在\u后面跟上超过0xFFFF的数值(比如\u20BB7),JavaScript 会理解成\u20BB+7 ,由于\u20BB是一个不可打印字符,所以只会显示一个空格,后面跟着一个7。

ES6 对这一点做出了改进,只要将码点放入大括号,就能正确解读该字符。

"\u{20BB7}" // "𠮷"

"\u{41}\u{42}\u{43}" // "ABC"

let hello = 123; hell\u{6F} // 123

'\u{1F680}' === '\uD83D\uDE80' // true

最后一个例子表明,大括号表示法与四字节的 UTF-16 编码是等价的。

有了这种表示法之后,JavaScript 共有 6 种方法可以表示一个字符。

'\z' === 'z'  // true
'\172' === 'z' // true
'\x7A' === 'z' // true
'\u007A' === 'z' // true
'\u{7A}' === 'z' // true

2、字符串的遍历器接口

ES6 为字符串添加了遍历器接口,使得字符串可以被for...of循环遍历,最大的优点是可以识别大于0xFFFF的码点,传统的for循环无法识别这样的码点。

  for (let s of 'foo') {
      console.log(s)
    }
  // "f"
  // "o"
  // "o"
  
   let text = String.fromCodePoint(0x20BB7);
    for (let i = 0; i < text.length; i++) {
      console.log(text[i]);
    }
    // " "
    // " "
    for (let i of text) {
      console.log(i);
    }
    // "𠮷"

3、直接输入 U+2028U+2029

JavaScript 字符串允许直接输入字符,以及输入字符的转义形式。举例来说,“中”的 Unicode 码点是 U+4e2d,你可以直接在字符串里面输入这个汉字,也可以输入它的转义形式\u4e2d,两者是等价的。

'中' === '\u4e2d' // true 但是,JavaScript 规定有5个字符,不能在字符串里面直接使用,只能使用转义形式。

  U+005C:反斜杠(reverse solidus)
    U+000D:回车(carriage return)
    U+2028:行分隔符(line separator)
    U+2029:段分隔符(paragraph separator)
    U+000A:换行符(line feed)

举例来说,字符串里面不能直接包含反斜杠,一定要转义写成\或者\u005c

单JSON 格式允许字符串里面直接使用 U+2028(行分隔符)和 U+2029(段分隔符)。这样一来,服务器输出的 JSON 被JSON.parse解析,就有可能直接报错。

const json = '"\u2028"'; JSON.parse(json); //

为了消除这个报错,ES2019 允许 JavaScript 字符串直接输入 U+2028(行分隔符)和 U+2029(段分隔符)。

const PS = eval("'\u2029'"); 根据这个提案,上面的代码不会报错。

4、JSON.stringify() 的改造

根据标准,JSON 数据必须是 UTF-8 编码。但是,现在的JSON.stringify()方法有可能返回不符合 UTF-8 标准的字符串。

UTF-8 标准规定,0xD8000xDFFF之间的码点,不能单独使用,必须配对使用。

比如,\uD834\uDF06是两个码点,但是必须放在一起配对使用,代表字符𝌆。单独使用\uD834\uDF06这两个码点是不合法的,或者颠倒顺序也不行,因为\uDF06\uD834并没有对应的字符。

JSON.stringify()的问题在于,它可能返回0xD8000xDFFF之间的单个码点。

JSON.stringify('\u{D834}') // "\u{D834}"

为了确保返回的是合法的 UTF-8 字符,ES2019(改变了JSON.stringify()的行为。如果遇到0xD8000xDFFF之间的单个码点,或者不存在的配对形式,它会返回转义字符串,留给应用自己决定下一步的处理。

    JSON.stringify('\u{D834}') // ""\uD834""
    JSON.stringify('\uDF06\uD834') // ""\udf06\ud834""

❤ 5、模板字符串

ES6支持模板字符串,使得字符串的拼接更加的简洁、直观。

ES6中通过${}就可以完成字符串的拼接,只需要将变量放在大括号之中

传统的 JavaScript 语言,输出模板

    $('#result').append(
      'There are <b>' + basket.count + '</b> ' +
      'items in your basket, ' +
      '<em>' + basket.onSale +
      '</em> are on sale!'
    );

上面这种写法相当繁琐不方便,ES6 引入了模板字符串解决这个问题。

   $('#result').append(`
      There are <b>${basket.count}</b> items
       in your basket, <em>${basket.onSale}</em>
      are on sale!
    `);

1、介绍

ES6引入了一种新型的字符串字面量语法,我们称之为模板字符串(template strings)。

我们可以使用反撇号字符 ` 代替普通字符串的引号 ' 或",在这种用法上,他们与一般的普通字符串的引号 ' 或 " 没有什么大的区别。但是它有一些更加便捷的应用法。

模板字符串(template string)是增强版的字符串,用反引号 ` 标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。

2、基本使用

  // 普通字符串
    `In JavaScript '\n' is a line-feed.`// 多行字符串
    `In JavaScript this is
     not legal.`console.log(`string text line 1
    string text line 2`);

// 字符串中嵌入变量

let name = "Bob", time = "today";
`Hello ${name}, how are you ${time}?`

上面代码中的模板字符串,都是用反引号表示。

如果在模板字符串中需要使用反引号,则前面要用反斜杠转义。

let greeting = ``Yo` World!`;

使用模板字符串表示多行字符串,所有的空格和缩进都会被保留在输出之中。

$('#list').html(`

<ul>
  <li>first</li>
  <li>second</li>
</ul>

`);

所有模板字符串的空格和换行,都是被保留的;

要将把行首和行尾的换行、空格等去掉,可以使用trim方法; 比如<ul>标签前面会有一个换行,不想要这个换行,可以使用trim方法消除它。

$('#list').html(`
​
<ul>
  <li>first</li>
  <li>second</li>
</ul>
​
`.trim());

模板字符串中嵌入变量,需要将变量名写在${}之中。

        function authorize(user, action) {
      if (!user.hasPrivilege(action)) {
        throw new Error(
          // 传统写法为
          // 'User '
          // + user.name
          // + ' is not authorized to do '
          // + action
          // + '.'
          `User ${user.name} is not authorized to do ${action}.`);
      }
    }

模板字符串中,大括号内部可以放入任意的 JavaScript 表达式,可以进行运算,以及引用对象属性。

let x = 1;
let y = 2;
​
`${x} + ${y} = ${x + y}`
// "1 + 2 = 3"`${x} + ${y * 2} = ${x + y * 2}`
// "1 + 4 = 5"let obj = {x: 1, y: 2};
`${obj.x + obj.y}`
// "3"

模板字符串之中还能调用函数。

function fn() {
  return "Hello World";
}
​
`foo ${fn()} bar`
// foo Hello World bar

如果模板字符串中的变量没有声明,将报错。

// 变量place没有声明
let msg = `Hello, ${place}`;
// 报错

如果大括号内部是一个字符串,将会原样输出。

`Hello ${'World'}`
// "Hello World"

模板字符串甚至还能嵌套。

const tmpl = addrs => `
  <table>
  ${addrs.map(addr => `
    <tr><td>${addr.first}</td></tr>
    <tr><td>${addr.last}</td></tr>
  `).join('')}
  </table>
`;
​

上面代码中,模板字符串的变量之中,又嵌入了另一个模板字符串,使用方法如下。

const data = [
    { first: '<Jane>', last: 'Bond' },
    { first: 'Lars', last: '<Croft>' },
];
console.log(tmpl(data));

6、实例:模板编译

我们来看一个通过模板字符串,生成正式模板的实例

let template = `
<ul>
  <% for(let i=0; i < data.supplies.length; i++) { %>
    <li><%= data.supplies[i] %></li>
  <% } %>
</ul>
`;

7、标签模板

模板字符串的功能,不仅仅是上面这些。它可以紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串。这被称为“标签模板”功能(tagged template)。

alert`hello`
// 等同于
alert(['hello'])

标签模板其实不是模板,而是函数调用的一种特殊形式。“标签”指的就是函数,紧跟在后面的模板字符串就是它的参数。

但是,如果模板字符里面有变量,就不是简单的调用了,而是会将模板字符串先处理成多个参数,再调用函数。

let a = 5;
let b = 10;
​
tag`Hello ${ a + b } world ${ a * b }`;
// 等同于
tag(['Hello ', ' world ', ''], 15, 50);

上面代码中,模板字符串前面有一个标识名tag,它是一个函数。整个表达式的返回值,就是tag函数处理模板字符串后的返回值。

函数tag依次会接收到多个参数。

function tag(stringArr, value1, value2){
  // ...
}
​
// 等同于function tag(stringArr, ...values){
  // ...
}

除此之外,你甚至可以使用标签模板,在 JavaScript 语言之中嵌入其他语言。

jsx`
  <div>
    <input
      ref='input'
      onChange='${this.handleChange}'
      defaultValue='${this.state.value}' />
      ${this.state.value}
   </div>
`

通过jsx函数,将一个 DOM 字符串转为 React 对象。你可以在 GitHub 找到jsx函数的具体实现。

8、模板字符串的限制

前面提到标签模板里面,可以内嵌其他语言。但是,模板字符串默认会将字符串转义,导致无法嵌入其他语言。

举例来说,标签模板里面可以嵌入 LaTEX 语言。

function latex(strings) {
  // ...
}
​
let document = latex`
\newcommand{\fun}{\textbf{Fun!}}  // 正常工作
\newcommand{\unicode}{\textbf{Unicode!}} // 报错
\newcommand{\xerxes}{\textbf{King!}} // 报错
​
Breve over the h goes \u{h}ere // 报错
`

变量document内嵌的模板字符串,对于 LaTEX 语言来说完全是合法的,但是 JavaScript 引擎会报错。原因就在于字符串的转义。