前端String那些事兒

js中的String其實不單單是"foo"這樣的字面量字符串。
Blob構造函數的入參array,數組元素能夠是USVString,到底什麼是USVString讓我很困惑。css

除了String外,其實還包括如下幾種類型的String。
工做中除了String.prototype上的那些好用的方法,es6的模板字符串等等,貌似也沒有其餘經常使用字符串的地方了。這裏就再也不贅述。html

參考mdn文檔和EcmaScript規範,再結合實際開發中的經驗,作一次簡單的專項學習。前端

USVString

  • USVString 表明的是全部可用unicode標量序列的集合
  • 在js中返回時,USVString會映射到一個String
  • 它一般只用於執行文本處理並須要操做unicode標量值字符串的api
  • USVString會等價DOMString,除了不容許未匹配的替代的碼點(在瀏覽器中,USVString中未匹配的替代碼點,會轉換成Unicode U+FFFD(�)字符)

DOMString

  • DOMString 是utf-16字符串
  • 在js中,DOMString最終也會映射爲String
  • 一個DOMString類型的方法或者參數容許傳null,一般是指'null'

CSSOMString

  • 要想了解CSSOMString,首先須要知道CSSOM是什麼。CSSOM是CSS Object Model,它是一個能夠經過js操做css的api集合。
  • CSSOMString在CSSOM中表示字符串數據,能夠引用DOMString或者USVString。
  • 當規範提到CSSOMString時,依賴於瀏覽器的vendor去使用DOMString或者USVString。
  • 在瀏覽器內存中若是經過UTF-8表示字符串數據,那麼能夠用USVString來替代CSSOMString。
  • 若是瀏覽器要用16位的序列表示字符串,可能會用DOMString。
  • 所謂utf-8,utf-16其實就是指用多少位表示字符串,8-bit Unicode Transformation Format。
  • 目前幾款主流的Firefox,Chrome,Safari,Opera都是用USVString來表示CSSOMString的。

Binary strings

  • JS中的字符串是utf-16編碼的。這就意味着一個代碼單元須要2個字節的內存,也就是說js中string的長度是以2個字節爲單位進行計算的。
  • 二進制字符串是用來表明二進制數據的,並非爲了表明字符。
  • 二進制字符表明的數據大小是原始數據的兩倍
  • 引入二進制字符串的緣由在於使用unit8類型數字的web應用在音頻,視頻以及WebSocket方面愈來愈強大,因此須要引入一個很好用api來提供支持
  • 過去操做二進制數據是經過字符串的操做模擬的。也就是經過charCodeAt方法從二進制字符串中讀取數據。效率低下,錯誤率高。對於不是嚴格意義上的二進制格式數據,32字節整數或者浮點數也會容易出錯。
  • js中的typed arrays提供了一個操做二進制數據的更加高效的方法。關於typed arrays,能夠參考JavaScript之typed arrays那些事兒

<script>的charset="utf-8"怎麼理解

  • 不區分大小寫的'utf-8'
  • 沒有必要爲charset屬性設置值,由於document必須是UTF-8
  • script標籤會從document繼承他的character encoding(字符編碼方式)
  • HTML Living Standard的建議是移除charset屬性

規範中的說明以下:node

If the script element has a charset attribute, then let encoding be the result of getting an encoding from the value of the charset attribute.
If the script element does not have a charset attribute, or if getting an encoding failed, let encoding be the same as the encoding of the script element's node document.
To get an encoding from a string label, run these steps:
Remove any leading and trailing ASCII whitespace from label.
If label is an ASCII case-insensitive match for any of the labels listed in the table below, return the corresponding encoding, and failure otherwise.
Name Labels
UTF-8 "unicode-1-1-utf-8","utf-8","utf8"
UTF-16LE "utf-16","utf-16le"

js中存在utf-8 encoder和utf-8 decoder專門進行utf-8的編解碼工做。git

js中的String採用utf-16格式編碼與 <script>的charset=「utf-8」不矛盾嗎

不矛盾。utf-16人類友好,utf-8機器友好。
寫js代碼時,utf-16人類友好。人類可識別。
script utf-8編碼時utf-8友好;端到端通訊時,utf-8機器友好。機器高效運行。es6

script編碼難道不對utf-16的js string進行編碼?
編碼。可是js代碼中不僅有字符串類型,還有Boolean,Number等等一系列類型。不矛盾!github

4.3.17String value
primitive value that is a finite ordered sequence of zero or more 16-bit unsigned integer values
NOTE
A String value is a member of the String type. Each integer value in the sequence usually represents a single 16-bit unit of UTF-16 text. However, ECMAScript does not place any restrictions or requirements on the values except that they must be 16-bit unsigned integers.
  • js字符串中是由0個或者多個16bit的無符號整數組成
  • 每一個整數的值一般表示UTF-16文本的一個16bit單元
  • es規定js字符必須是一個16bit的無符號整數

初見端倪

經過encodeURIComponent和decodeURIComponent能夠初見端倪。
首先明確一點。
utf-8格式url(機器友好):"http://foo.test.go.com/index.html#/?from=http%3A%2F%2Fbar.crm.test.go.com%2F&redirectUrl=http%3A%2F%2Fbaz.test.go.com%2Fuser%2FgetCASUser&platformCode=10004"
utf-16格式url(人類友好):"http://foo.test.go.com/index.html#/?from=http://bar.crm.test.go.com/&redirectUrl=http://baz.test.go.com/user/getCASUser&platformCode=10004"web

encodeURIComponent(uriComponent) 將UTF-16編碼的url(其實就是js中的url字符串,「https://www.foo.com?foo=123」)編碼爲UTF-8格式"https%3A%2F%2Fwww.foo.com%3Ffoo%3D123"
decodeURI(encodedURIComponent)將UTF8格式的url 解碼爲utf-16格式「https://www.foo.com?foo=123」chrome

爲何不用encodeURI?

由於:segmentfault

Note that encodeURI by itself cannot form proper HTTP GET and POST requests, such as for XMLHTTPRequests, because "&", "+", and "=" are not encoded, which are treated as special characters in GET and POST requests. encodeURIComponent, however, does encode these characters.

不能生成用於HTTP GET或者POST請求的url,由於:

encodeURI Not Escaped: A-Z a-z 0-9 ; , / ? : @ & = + $ - _ . ! ~ * ' ( ) #

小結

  • utf-8編碼機器友好:瀏覽器http url,script默認編碼格式等等
  • utf-16編碼人類友好:肉眼可識別字符串
  • script utf-8編碼難道不對utf-16的js string進行編碼? 編碼。可是js代碼中不僅有字符串類型,還有Boolean,Number等等一系列類型。不矛盾!

總結

  • chrome中的CSSOMString最終都會映射成USVString
  • js中的USVString最終會映射成String
  • js中的String採用utf-16格式編碼,也就是說js中字符串的最小組織單元是2個字節(byte)
  • js中的二進制數據能夠經過js的typed arrays進行操做
  • <script>的charset="utf-8"沒有必要再顯式設置,會繼承document的編碼方式
  • script utf-8編碼難道不對utf-16的js string進行編碼?
  • 編碼。可是js代碼中不僅有字符串類型,還有Boolean,Number等等一系列類型。不矛盾!

期待和你們交流,共同進步,歡迎你們加入我建立的與前端開發密切相關的技術討論小組:

努力成爲優秀前端工程師!