Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

前端String那些事儿 #163

Open
FrankKai opened this issue Oct 23, 2019 · 2 comments
Open

前端String那些事儿 #163

FrankKai opened this issue Oct 23, 2019 · 2 comments

Comments

@FrankKai
Copy link
Owner

js中的String其实不仅仅是"foo"这样的字面量字符串。
Blob构造函数的入参array,数组元素可以是USVString,到底什么是USVString让我很困惑。

除了String外,其实还包括以下几种类型的String。
工作中除了String.prototype上的那些好用的方法,es6的模板字符串等等,貌似也没有其他常用字符串的地方了。这里就不再赘述。

参考mdn文档和EcmaScript规范,再结合实际开发中的经验,做一次简单的专项学习。

@FrankKai
Copy link
Owner Author

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属性

规范中的说明如下:

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的编解码工作。

js中的String采用utf-16格式编码与 <script>的charset=“utf-8”不矛盾吗

不矛盾。utf-16人类友好,utf-8机器友好。
写js代码时,utf-16人类友好。人类可识别。
script utf-8编码时utf-8友好;端到端通信时,utf-8机器友好。机器高效运行。

script编码难道不对utf-16的js string进行编码?
编码。但是js代码中不只有字符串类型,还有Boolean,Number等等一系列类型。不矛盾!

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"

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”

为什么不用encodeURI?

因为:

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等等一系列类型。不矛盾!

@FrankKai
Copy link
Owner Author

总结

  • 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等等一系列类型。不矛盾!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant