在介绍字符串之前,有必要先了解一点Unicode的基础知识,有助于理解ES6提供的新功能和新特性。
## 一、Unicode
  Unicode是一种字符集(即多个字符的集合),它的目标是涵盖世界上的所有字符,为其提供唯一的标识符,这个标识符叫做码位或码点(Code Point)。码位既可以用一个从0开始计算的数值表示,也可以用U+作为前缀后面紧跟十六进制数表示。
  Unicode只规定了每个字符的码位,但并没有规定如何用字节序列(即二进制数字存储方式)表示字符,于是就出现了字符编码(Character Encoding)。Unicode包含多种字符编码,例如UTF-8、UTF-16等,此处的UTF前缀是Unicode Transformation Format的缩写,即统一转换格式,它们都是Unicode的一种实现方式。其中UTF-8是变长编码,使用1~4个字节表示一个字符,它的最小编码单元(Code Unit)为一个字节(即8位);而UTF-16使用2或4个字节表示一个字符,它的最小编码单元为两个字节(即16位)。
  Unicode的码位范围从U+0000到U+10FFFF,由于包含的字符众多,因此会把它们划分成17组,组也叫平面(Plane),每个平面包含2^16=65536个字符,其中第0个平面叫做基本多语言平面(Basic Multilingual Plane,简称BMP),码位范围从U+0000到U+FFFF(包含了ASCII码),剩下的16个为辅助平面(Supplementary Plane)。
  JavaScript采用了UTF-16编码的Unicode字符集,BMP中的字符可用一个16位的编码单元表示,而辅助平面中的字符则要遵循UTF-16的代理对(Surrogate Pair)规则,即用两个编码单元表示。这意味着JavaScript中的一个Unicode字符,它的长度有可能是1,但也有可能是2。由于JavaScript中的字符串方法(例如substring()、charAt()等)都会受到这种编码规则的影响,因此有时候会返回出人意料的结果。不过好在ES6大幅增强了对Unicode的支持,有效避免了这种意外性情况的发生。
## 二、Unicode字符
  在JavaScript中,Unicode字符可以用Unicode转义字符的形式(即\\uXXXX)表示,其中4个“X”表示字符的码位,而“X”是一个16进制字符,还要注意一点,ES5只支持4个“X”。也就是说,这种形式只能表示BMP中的字符(即U+0000到U+FFFF内的字符),如果要使用辅助平面中的字符,那么需要写两个Unicode转义字符。下面代码中,第一个字符是BMP中的“向”,第二个字符是2号平面中的“𠮳”。
~~~
let word1 = "\u5411";
console.log(word1); //"向"
let word2 = "\ud842\udfb3";
console.log(word2); //"𠮳"
~~~
  ES6为Unicode字符提供了一种新形式,只需把码位用花括号包裹,就能支持辅助平面中的字符。下面使用了新形式来描述字符“𠮳”。
~~~
let word3 = "\u{20BB3}";
console.log(word3); //"𠮳"
~~~
## 三、Unicode标准化
  Unicode标准化(Unicode Normalization),也叫Unicode正规化或Unicode规范化,可将字符转换成指定的字节序列,统一表现形式,以及确定字符之间的等价性。例如字符“ü”,既可以只用U+00FC表示,也可以用U+0075(u)和U+0308(¨)组合表示,虽然对于人类来说,两种表示法得到的结果在视觉上是完全相同的,但对于计算机来说却是不同的,如下所示。
~~~
var mark1 = "\u00FC",
mark2 = "\u0075\u0308";
mark1 === mark2; //false
~~~
  ES6新增了一个原型方法normalize(),可以将字符串标准化,修改上面的例子,就能得到相等的结果,如下所示。
~~~
mark1.normalize() === mark2.normalize(); //true
~~~
  normalize()方法可以接收一个字符串参数,但只有4个可选值(如表4所示),其中“NFC”是方法的默认值。
:-: ![](https://box.kancloud.cn/0fee91db9eeabbf1d59f8fb9742ee635_600x370.png)
:-: 表4 标准化参数
  上表中的标准等价(Canonical Equivalence)和兼容等价(Compatibility Equivalence)都表示相同的字符或字符序列,并且前者是后者的一个子集。标准等价会保持视觉外观和文本含义,前面字符“ü”的示例就用到了标准等价;而兼容等价会改变视觉外观和文本含义,例如罗马数字十二(Ⅻ)可由一个罗马数十(Ⅹ)和两个罗马数一(Ⅰ)组成,两者只有通过兼容等价的标准化处理后才能匹配成功,如下所示。
~~~
var digit1 = "\u216B", //"Ⅻ"
digit2 = "\u2169\u2160\u2160"; //"ⅩⅠⅠ"
digit1 = digit1.normalize("NFKC"); //"XII"
digit2 = digit2.normalize("NFKC"); //"XII"
digit1 === digit2; //true
~~~
## 四、码位的处理
  字符串的原型方法charCodeAt()可以读取到BMP中的字符的码位,而辅助平面中的字符却无法正确读取,它们会被当成两个字符来对待。还是以“𠮳”为例,如下所示,分别返回字符串第0和第1处位置的码位。
~~~
var str = "𠮳";
str.charCodeAt(0); //55362
str.charCodeAt(1); //57267
~~~
  ES6提供了codePointAt()方法,有效解决了上述问题,如下所示。
~~~
str.codePointAt(0); //134067
str.codePointAt(1); //57267
~~~
  不过需要注意,codePointAt()方法还能返回字符的第二个编码单元的码位,即上面代码中第2条语句。
  String对象的静态方法fromCharCode()可将码位转换成字符,功能和charCodeAt()方法正好相反,但也不能正确处理辅助平面中的字符。为此,ES6扩展了String对象,新增了一个静态方法fromCodePoint(),和codePointAt()方法对应,如下所示,由于第1条语句得到的结果是一个无法打印的字符,因此没有展示。
~~~
String.fromCharCode(134067);
String.fromCodePoint(134067); //"𠮳"
~~~
## 五、解析字符串
  ES6增强了JavaScript解析字符串的能力,新增了3个检索子串的方法(如表5所示),它们都返回布尔值。在某些场景,这些方法是indexOf()的理想替代品。
:-: ![](https://box.kancloud.cn/f847374d80a3c05e00b8460a68f4ce17_600x285.png)
:-: 表5 新的检索方法
  三个方法都能接收两个参数,先介绍第一个参数,表示要检索的子串,注意,子串不能是正则表达式,下面展示了只传一个参数时的情况。
~~~
var str = "My name is strick";
str.length; //17
str.includes("name"); //true
str.startsWith("name"); //false
str.endsWith("name"); //false
~~~
  方法的第二个参数是一个可选值,它有两种含义。在includes()和startsWith()方法中用于指定检索的起始位置,默认值为0;而在endsWith()方法中用于指定原字符串str的长度,默认值为str.length。修改上面的代码,为startsWith()和endsWith()分别传入第二个参数,前者的值为3,后者的值为7,它们的结果都变成了true,如下所示。
~~~
str.startsWith("name", 3); //true
str.endsWith("name", 7); //true
~~~
  除了检索的新方法,ES6还提供了一个重复字符串的新方法:repeat(),它的参数是一个正整数,表示重复的次数,使用方法如下所示。
~~~
"name".repeat(2); //"namename"
~~~
  最后介绍的是String对象的静态方法raw(),在[第4篇模板字面量](https://www.cnblogs.com/strick/p/10173486.html)的标签模板中曾提到过。不过当时只强调了它是一个内置的标签模板,用于获取原始信息,但其实它也可以作为普通的函数来使用。只不过它的第一个参数得是一个包含raw属性的对象,raw属性的值既可以是数组也可以是字符串,第二个是可选的剩余参数,这些参数可插到指定位置,例如方法的第二个参数需要插到raw属性值中的第一和第二个元素之间,具体可参考下面的例子。
~~~
String.raw({raw: "abc"}, 0, 1, 2); //"a0b1c"
//相当于
String.raw({raw: ["a", "b", "c"]}, 0, 1, 2); //"a0b1c"
~~~
*****
> 原文出处:
[博客园-ES6躬行记](https://www.cnblogs.com/strick/category/1372951.html)
[知乎专栏-ES6躬行记](https://zhuanlan.zhihu.com/pwes6)
已建立一个微信前端交流群,如要进群,请先加微信号freedom20180706或扫描下面的二维码,请求中需注明“看云加群”,在通过请求后就会把你拉进来。还搜集整理了一套[面试资料](https://github.com/pwstrick/daily),欢迎浏览。
![](https://box.kancloud.cn/2e1f8ecf9512ecdd2fcaae8250e7d48a_430x430.jpg =200x200)
推荐一款前端监控脚本:[shin-monitor](https://github.com/pwstrick/shin-monitor),不仅能监控前端的错误、通信、打印等行为,还能计算各类性能参数,包括 FMP、LCP、FP 等。
- ES6
- 1、let和const
- 2、扩展运算符和剩余参数
- 3、解构
- 4、模板字面量
- 5、对象字面量的扩展
- 6、Symbol
- 7、代码模块化
- 8、数字
- 9、字符串
- 10、正则表达式
- 11、对象
- 12、数组
- 13、类型化数组
- 14、函数
- 15、箭头函数和尾调用优化
- 16、Set
- 17、Map
- 18、迭代器
- 19、生成器
- 20、类
- 21、类的继承
- 22、Promise
- 23、Promise的静态方法和应用
- 24、代理和反射
- HTML
- 1、SVG
- 2、WebRTC基础实践
- 3、WebRTC视频通话
- 4、Web音视频基础
- CSS进阶
- 1、CSS基础拾遗
- 2、伪类和伪元素
- 3、CSS属性拾遗
- 4、浮动形状
- 5、渐变
- 6、滤镜
- 7、合成
- 8、裁剪和遮罩
- 9、网格布局
- 10、CSS方法论
- 11、管理后台响应式改造
- React
- 1、函数式编程
- 2、JSX
- 3、组件
- 4、生命周期
- 5、React和DOM
- 6、事件
- 7、表单
- 8、样式
- 9、组件通信
- 10、高阶组件
- 11、Redux基础
- 12、Redux中间件
- 13、React Router
- 14、测试框架
- 15、React Hooks
- 16、React源码分析
- 利器
- 1、npm
- 2、Babel
- 3、webpack基础
- 4、webpack进阶
- 5、Git
- 6、Fiddler
- 7、自制脚手架
- 8、VSCode插件研发
- 9、WebView中的页面调试方法
- Vue.js
- 1、数据绑定
- 2、指令
- 3、样式和表单
- 4、组件
- 5、组件通信
- 6、内容分发
- 7、渲染函数和JSX
- 8、Vue Router
- 9、Vuex
- TypeScript
- 1、数据类型
- 2、接口
- 3、类
- 4、泛型
- 5、类型兼容性
- 6、高级类型
- 7、命名空间
- 8、装饰器
- Node.js
- 1、Buffer、流和EventEmitter
- 2、文件系统和网络
- 3、命令行工具
- 4、自建前端监控系统
- 5、定时任务的调试
- 6、自制短链系统
- 7、定时任务的进化史
- 8、通用接口
- 9、微前端实践
- 10、接口日志查询
- 11、E2E测试
- 12、BFF
- 13、MySQL归档
- 14、压力测试
- 15、活动规则引擎
- 16、活动配置化
- 17、UmiJS版本升级
- 18、半吊子的可视化搭建系统
- 19、KOA源码分析(上)
- 20、KOA源码分析(下)
- 21、花10分钟入门Node.js
- 22、Node环境升级日志
- 23、Worker threads
- 24、低代码
- 25、Web自动化测试
- 26、接口拦截和页面回放实验
- 27、接口管理
- 28、Cypress自动化测试实践
- 29、基于Electron的开播助手
- Node.js精进
- 1、模块化
- 2、异步编程
- 3、流
- 4、事件触发器
- 5、HTTP
- 6、文件
- 7、日志
- 8、错误处理
- 9、性能监控(上)
- 10、性能监控(下)
- 11、Socket.IO
- 12、ElasticSearch
- 监控系统
- 1、SDK
- 2、存储和分析
- 3、性能监控
- 4、内存泄漏
- 5、小程序
- 6、较长的白屏时间
- 7、页面奔溃
- 8、shin-monitor源码分析
- 前端性能精进
- 1、优化方法论之测量
- 2、优化方法论之分析
- 3、浏览器之图像
- 4、浏览器之呈现
- 5、浏览器之JavaScript
- 6、网络
- 7、构建
- 前端体验优化
- 1、概述
- 2、基建
- 3、后端
- 4、数据
- 5、后台
- Web优化
- 1、CSS优化
- 2、JavaScript优化
- 3、图像和网络
- 4、用户体验和工具
- 5、网站优化
- 6、优化闭环实践
- 数据结构与算法
- 1、链表
- 2、栈、队列、散列表和位运算
- 3、二叉树
- 4、二分查找
- 5、回溯算法
- 6、贪心算法
- 7、分治算法
- 8、动态规划
- 程序员之路
- 大学
- 2011年
- 2012年
- 2013年
- 2014年
- 项目反思
- 前端基础学习分享
- 2015年
- 再一次项目反思
- 然并卵
- PC网站CSS分享
- 2016年
- 制造自己的榫卯
- PrimusUI
- 2017年
- 工匠精神
- 2018年
- 2019年
- 前端学习之路分享
- 2020年
- 2021年
- 2022年
- 2023年
- 日志
- 2020