在介紹字符串之前,有必要先了解一點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”是方法的默認值。
:-: 
:-: 表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()的理想替代品。
:-: 
:-: 表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),歡迎瀏覽。

推薦一款前端監控腳本:[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年
- 2024年
- 日志
- 2020