读书频道 > web开发 > Javascript > Effective JavaScript:编写高质量JavaScript代码的68个有效方法
第7条:视字符串为16位的代码单元序列
2013-12-07 14:19:36     我来说两句 
收藏    我要投稿   
本书共分为7章,分别涵盖JavaScript的不同主题。第1章主要讲述最基本的主题,如版本、类型转换要点、运算符注意事项和分号局限等。第2章主要讲解变量作用域,介绍此方面的一些基本概念,以及一些最佳实践经验。第  立即去当当网订购

Unicode有一个声誉,就是其复杂性。尽管字符串无处不在,大多数程序员还是抱着乐观的态度避免学习Unicode。但是在概念层面,它没有什么可害怕的。Unicode的基础非常简单。它为世界上所有的文字系统的每个字符单位分配了一个唯一的整数,该整数介于0和1 114 111之间,在Unicode术语中称为代码点(code point)。Unicode与其他字符编码几乎没有任何不同(例如,ASCII)。然而不同的是,ASCII将每个索引映射为唯一的二进制表示,但Unicode允许多个不同二进制编码的代码点。不同的编码在要求存储的字符串数量和操作速度(如索引到某个字符串)之间进行权衡。目前有多种Unicode的编码标准,最流行的几个是:UTF-8、UTF-16和UTF-32。

进一步使情况复杂的是,Unicode的设计师根据历史的数据,错误估算了代码点的容量范围。人们起初认为Unicode最多只需要216个代码点,所以产生了UCS-2,其为16位编码的原始标准。这是一个特别有吸引力的选择。由于每个代码点可以容纳一个16位的数字,所以简单的方法就是将代码点与其编码元素一对一地映射起来,这称为一个代码单元(code unit)。也就是说,UCS-2是由独立的16位的代码单元组成的,每个代码单元对应一个单独的Unicode代码点。这种编码方式的主要好处在于索引字符串是一种代价小的、固定时间的操作。获取某个字符串的第n个代码点只是简单地选取数组的第n个16位元素。图1.1显示了一个字符串例子。这些字符仅由最初的16位范围中的代码点组成。正如你看到的一样,对于Unicode的字符串,编码元素和代码点能完全的匹配。

 

其结果是,当时许多平台都采用16位编码的字符串。Java便是其中之一,JavaScript也紧随其后,所以JavaScript字符串的每个元素都是一个16位的值。现在,如果Unicode还是保持20世纪90年代初的做法,那么JavaScript字符串的每个元素仍然对应一个单独的代码点。

16位的范围是相当大的,囊括了世界上的大多数文字系统,这比ASCII或其无数的历史替代者都要多。即便如此,Unicode也需要及时扩大其最初的范围,标准从当时的216扩展到了超过220个代码点。新增加的范围被组织为17个大小为216代码点的子范围。第一个子范围,称为基本多文种平面(Basic Multilingual Plane, BMP),包含最初的216个代码点。余下的16个范围称为辅助平面(supplementary plane)。

一旦代码点的范围扩展,UCS-2就变得过时了。它需要通过扩展来表示这些附加的代码点。其替代者UTF-16与之类似,但UTF-16采用代理对表示附加的代码点。一对16位的代码单元共同编码一个等于或大于216的代码点。例如,分配给高音谱号的音乐符号(“”)的代码点为U+1D11E(代码点数119 070的Unicode的惯用16进制写法)。其由UTF-16格式的代码单元0xd834和0xddle共同表示。可以通过合并这两个代码单元选择的位来对这个代码点进行解码。(巧妙的是,这种编码保证了这些代理对绝不会与有效的BMP代码点混淆,因此,甚至从字符串中间的某个位置进行搜索,你也可以随时识别一个代理对。)在图1.2中你可以看到一个含有代理对的字符串的例子。该字符串的第一个代码点需要一个代理对,从而导致了代码单元的索引与代码点的索引不同。

由于UTF-16的每个代码点编码需要一个或两个16位的代码单元,因此UTF-16是一种可变长度的编码。长度为n的字符串在内存中的大小变化基于该字符串特定的代码点。此外,查找字符串的第n个代码点不再是一个固定时间的操作,因为它一般需要从字符串的开始处进行搜索。

但是当Unicode扩大规模时,JavaScript已经采用了16位的字符串元素。字符串属性和方法(如length、charAt和charCodeAt)都是基于代码单元层级,而不是代码点层级。所以每当字符串包含辅助平面中的代码点时,JavaScript将每个代码点表示为两个元素而不是一个(一对UTF-16代理对的代码点)。简单地说,一个JavaScript字符串的元素是一个16位的代码单元。


 

类似地,正则表达式也工作于代码单元层级。其单字符模式(“.”)匹配一个单一的代码单元。

 

这种状况意味着应用程序同Unicode的整个范围一起工作必须更加仔细。应用程序不能信赖字符串方法、长度值、索引查找或者许多正则表达式模式。如果你使用除BMP之外的代码点,那么求助于一些支持代码点的库是个好主意。正确地获取编码和解码的细节是相当棘手的,所以最好使用一个现存的库,而不是自己实现这些逻辑。

虽然JavaScript内置的字符串数据类型工作于代码单元层级,但这并不能阻止一些API意识到代码点和代理对。事实上,一些标准的ECMAScript库正确地处理了代理对,例如URI操作函数:sendcodeURI、decodeURI、encodeURIComponent和decodeURIComponent。每当一个JavaScript环境提供一个库操作字符串(例如,操作一个Web页面的内容或者执行关于字符串的I/O操作),你都需要查阅这些库文档,看它们如何处理Unicode代码点的整个范围。

 提示

JavaScript字符串由16位的代码单元组成,而不是由Unicode代码点组成。

JavaScript使用两个代码单元表示216及其以上的Unicode代码点。这两个代码单元被称为代理对。
代理对甩开了字符串元素计数,length、charAt、charCodeAt方法以及正则表达式模式(例如“.”)受到了影响。

使用第三方的库编写可识别代码点的字符串操作。

每当你使用一个含有字符串操作的库时,你都需要查阅该库文档,看它如何处理代码点的整个范围。

点击复制链接 与好友分享!回本站首页
分享到: 更多
您对本文章有什么意见或着疑问吗?请到论坛讨论您的关注和建议是我们前行的参考和动力  
上一篇:第6条:了解分号插入的局限
下一篇:概述
相关文章
图文推荐
3.12 本章小结
3.10 添加新函数
3.9 递归
3.8 闭包
排行
热门
文章
下载
读书

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训
版权所有: 红黑联盟--致力于做最好的IT技术学习网站