美文网首页
ES6学习笔记03——字符串的扩展

ES6学习笔记03——字符串的扩展

作者: 小挠许 | 来源:发表于2018-11-16 08:20 被阅读0次

    字符的 Unicode 表示法

    JavaScript 允许采用\uxxxx形式表示一个字符,其中xxxx表示字符的 Unicode 码点。

    "\u0061"
    // "a"
    

    但是,这种表示法只限于码点在\u0000~\uFFFF之间的字符。超出这个范围的字符,必须用两个双字节的形式表示。

    "\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;
    "\u{6F}";//o
    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
    

    codePointAt()

    JavaScript 内部,字符以 UTF-16 的格式储存,每个字符固定为2个字节。对于那些需要4个字节储存的字符(Unicode 码点大于0xFFFF的字符),JavaScript 会认为它们是两个字符。

    var s = "𠮷";
    
    s.length // 2
    s.charAt(0) // ''
    s.charAt(1) // ''
    s.charCodeAt(0) // 55362
    s.charCodeAt(1) // 57271
    

    上面代码中,汉字“𠮷”(注意,这个字不是“吉祥”的“吉”)的码点是0x20BB7,UTF-16 编码为0xD842 0xDFB7(十进制为55362 57271),需要4个字节储存。对于这种4个字节的字符,JavaScript 不能正确处理,字符串长度会误判为2,而且charAt方法无法读取整个字符,charCodeAt方法只能分别返回前两个字节和后两个字节的值。
    ES6 提供了codePointAt方法,能够正确处理 4 个字节储存的字符,返回一个字符的码点。

    let s = '𠮷a';
    
    s.codePointAt(0) // 134071
    s.codePointAt(1) // 57271
    
    s.codePointAt(2) // 97
    

    codePointAt方法的参数,是字符在字符串中的位置(从 0 开始)。上面代码中,JavaScript 将“𠮷a”视为三个字符,codePointAt 方法在第一个字符上,正确地识别了“𠮷”,返回了它的十进制码点 134071(即十六进制的20BB7)。在第二个字符(即“𠮷”的后两个字节)和第三个字符“a”上,codePointAt方法的结果与charCodeAt方法相同。
    总之,codePointAt方法会正确返回 32 位的 UTF-16 字符的码点。对于那些两个字节储存的常规字符,它的返回结果与charCodeAt方法相同。
    codePointAt方法返回的是码点的十进制值,如果想要十六进制的值,可以使用toString方法转换一下。

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

    你可能注意到了,codePointAt方法的参数,仍然是不正确的。比如,上面代码中,字符a在字符串s的正确位置序号应该是 1,但是必须向codePointAt方法传入 2。解决这个问题的一个办法是使用for...of循环,因为它会正确识别 32 位的 UTF-16 字符。

    let s = '𠮷a';
    for (let ch of s) {
      console.log(ch.codePointAt(0).toString(16));
    }
    // 20bb7
    // 61
    

    codePointAt方法是测试一个字符由两个字节还是由四个字节组成的最简单方法。

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

    String.fromCodePoint()

    ES5 提供String.fromCharCode方法,用于从码点返回对应字符,但是这个方法不能识别 32 位的 UTF-16 字符(Unicode 编号大于0xFFFF)。

    String.fromCharCode(0x20BB7)
    // "ஷ"
    

    上面代码中,String.fromCharCode不能识别大于0xFFFF的码点,所以0x20BB7就发生了溢出,最高位2被舍弃了,最后返回码点U+0BB7对应的字符,而不是码点U+20BB7对应的字符。
    ES6 提供了String.fromCodePoint方法,可以识别大于0xFFFF的字符,弥补了String.fromCharCode方法的不足。在作用上,正好与codePointAt方法相反。

    相关文章

      网友评论

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

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