ES6学习笔记——字符串的拓展

作者: island_0d48 | 来源:发表于2017-08-30 00:18 被阅读43次

    字符串的扩展

    ES5中只限于\u0000~\uFFFF之间的字符。超过这个范围的字符,必须用两个双字节表示。

    如果直接在\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
    

    同时ES6给出了一系列方法来处理超过0xFFFF的字符,解决ES5的遗留问题。

    codePointAt()方法

    ES5没办法处理需要4个字节存储的字符,charAt方法无法读取整个字符,charCodeAt方法只能分别返回前两个字节和后两个字节的值,ES6提供了codePointAt方法,能够正确处理4个字节储存的字符,返回一个字符的码点。codePointAt方法会正确返回32位的UTF-16字符的码点。对于那些两个字节储存的常规字符,它的返回结果与charCodeAt方法相同。

    codePointAt方法返回的是码点的十进制值,如果想要十六进制的值,可以使用toString方法转换一下。

    var s = '𠮷a';
    
    s.codePointAt(0).toString(16) // "20bb7"
    s.codePointAt(2).toString(16) // "61"
    

    同时,该方法还是测试一个字符由两个字节还是四个字节组成的简单方法。

    function is32Bit(c) {
      return c.codePointAt(0) > 0xFFFF;
    }
    
    is32Bit("𠮷") // true
    is32Bit("a") // false
    

    String.fromCodePoint()

    跟codePointAt()相似,这个函数也是用来解决ES5中无法处理大于FFFF的字符的。这个方法可以直接从码点返回字符,在ES5中会将高位抛弃从而得不到结果。

    注意,fromCodePoint方法定义在String对象上,而codePointAt方法定义在字符串的实例对象上。

    at()

    at()方法同样是用来解决超过0xFFFF的字符问题的。ES5中的charAt方法在对付双字节存储的字符时只会得到一部分。

    ES6中的一个提案是用一个at函数去返回正确的字符。

    normalize()

    normalize()方法同样是用来处理疑难字符的,比如欧洲的一些带有音调的字符。为了表示它们,Unicode 提供了两种方法。一种是直接提供带重音符号的字符,比如Ǒ(\u01D1)。另一种是提供合成符号(combining character),即原字符与重音符号的合成,两个字符合成一个字符,比如O(\u004F)和ˇ(\u030C)合成Ǒ(\u004F\u030C)。

    这两种表示方法,在视觉和语义上都等价,但是 JavaScript 不能识别。

    '\u01D1'==='\u004F\u030C' //false
    
    '\u01D1'.length // 1
    '\u004F\u030C'.length // 2
    

    上面代码表示,JavaScript 将合成字符视为两个字符,导致两种表示方法不相等。

    ES6 提供字符串实例的normalize()方法,用来将字符的不同表示方法统一为同样的形式,这称为 Unicode 正规化。

    '\u01D1'.normalize() === '\u004F\u030C'.normalize()
    // true
    

    不过,normalize方法目前不能识别三个或三个以上字符的合成。这种情况下,还是只能使用正则表达式,通过Unicode编号区间判断。

    includes(), startsWith(), endsWith()

    原来的ES5中提供了一个indexOf方法,可以用来确定一个字符是否包含在另一个字符串中,ES6中又加了3个好用的方法。

    • includes(): 返回布尔值,表示是否找到了参数字符串
    • startsWith(): 返回布尔值,表示参数字符串是否在原字符串的头部
    • endsWith(): 返回布尔值,表示参数字符串是否在元字符串的尾部

    这三个方法都支持第二个参数,表示开始搜索的位置。

    var s = 'Hello world!';
    
    s.startsWith('Hello') // true
    s.endsWith('!') // true
    s.includes('o') // true
    
    s.startsWith('world', 6) // true
    s.endsWith('Hello', 5) // true
    s.includes('Hello', 6) // false
    

    上面代码表示,使用第二个参数n时,endsWith的行为与其他两个方法有所不同。它针对前n个字符,而其他两个方法针对从第n个位置直到字符串结束。

    repeat()

    这个方法就是单纯地把某个字符串重复几遍,没啥好说的。上代码。

    'x'.repeat(3) // "xxx"
    'hello'.repeat(2) // "hellohello"
    'na'.repeat(0) // ""
    

    padStart(), padEnd()

    如果某个字符串不够指定长度,可以用padStart(), padEnd()方法在头部或尾部补全。看一下代码也很快就能看懂。如果你省略第二个参数,默认会用空格补全。

    'x'.padStart(5, 'ab') // 'ababx'
    'x'.padStart(4, 'ab') // 'abax'
    
    'x'.padEnd(5, 'ab') // 'xabab'
    'x'.padEnd(4, 'ab') // 'xaba'
    

    模板字符串

    在ES6可以使用${}来编写模板输出字符串,这跟很多模板语言很像。然后引入了``来标识这种增强版的字符串。也可以用来定义多行字符串,或者在字符中嵌入变量。
    代码的话,大概会这样:

    $('#result').append(`
      There are <b>${basket.count}</b> items
       in your basket, <em>${basket.onSale}</em>
      are on sale!
    `);
    
    // 普通字符串
    `In JavaScript '\n' is a line-feed.`
    
    // 多行字符串
    `In JavaScript this is
     not legal.`
    
    console.log(`string text line 1
    string text line 2`);
    
    // 字符串中嵌入变量
    var name = "Bob", time = "today";
    `Hello ${name}, how are you ${time}?`
    

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

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

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

    在大括号内可以使用表达式,甚至可以调方法,还可以嵌套,很是酷炫。

    var x = 1;
    var y = 2;
    
    `${x} + ${y} = ${x + y}`
    // "1 + 2 = 3"
    
    `${x} + ${y * 2} = ${x + y * 2}`
    // "1 + 4 = 5"
    
    var obj = {x: 1, y: 2};
    `${obj.x + obj.y}`
    // "3"
    
    function fn() {
      return "Hello World";
    }
    
    `foo ${fn()} bar`
    // foo Hello World bar
    
    const tmpl = addrs => `
      <table>
      ${addrs.map(addr => `
        <tr><td>${addr.first}</td></tr>
        <tr><td>${addr.last}</td></tr>
      `).join('')}
      </table>
    `;
    

    如果需要引用模板字符串本身,在需要时执行,可以像下面这样写。

    // 写法一
    let str = 'return ' + '`Hello ${name}!`';
    let func = new Function('name', str);
    func('Jack') // "Hello Jack!"
    
    // 写法二
    let str = '(name) => `Hello ${name}!`';
    let func = eval.call(null, str);
    func('Jack') // "Hello Jack!"
    

    标签模板

    模板字符串可以直接跟在某个函数名后面,然后该函数可以用来处理这个模板字符串。如果模板字符里面有变量,就不是简单的调用,而是会把模板字符串先处理成多个参数,然后再调用函数。

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

    函数调用的参数如下:

    • 第一个参数是一个数组,该数组的成员是模板字符串中那些没有变量替换的部分,也就是说,变量替换只发生在数组的第一个成员与第二个成员之间、第二个成员与第三个成员之间,以此类推
    • tag函数的其他参数,都是模板字符串各个变量被替换后的值。由于本例中,模板字符串含有两个变量,因此tag会接受到value1和value2两个参数

    另外一个例子:

    var a = 5;
    var b = 10;
    
    function tag(s, v1, v2) {
      console.log(s[0]);
      console.log(s[1]);
      console.log(s[2]);
      console.log(v1);
      console.log(v2);
    
      return "OK";
    }
    
    tag`Hello ${ a + b } world ${ a * b}`;
    // "Hello "
    // " world "
    // ""
    // 15
    // 50
    // "OK"
    

    标签模板有主要这么几种功能:

    • 过滤HTML字符串
    • 多语言转换(国际化处理)
    • 在js中嵌入其他语言

    String.raw()

    String.raw()方法,往往用来充当模板字符串的处理函数,返回一个斜杠都被转义的字符串,对应于替换变量后的模板字符串。

    String.raw`Hi\n${2+3}!`;
    // "Hi\\n5!"
    
    String.raw`Hi\u000A!`;
    // 'Hi\\u000A!'
    

    模板字符串的限制

    当然啦,模板字符串也有它的局限性,归纳如下

    • 虽然可以用模板字符串嵌入其他语言,但是由于存在字符串的转义,导致有些语言无法使用,比如嵌入Latex

    相关文章

      网友评论

        本文标题:ES6学习笔记——字符串的拓展

        本文链接:https://www.haomeiwen.com/subject/qlqzdxtx.html