Effective JavaScript String Encoding Item 7

本系列作为Effective JavaScript的读书笔记。

提起Unicode,也许许多程序员都会觉得这玩意很麻烦,可是本质上,Unicode并不复杂。世界上每种语言的每一个文字都被一个整形数值表示,范围是0到1114111,这个值在Unicode术语中被称为Code
Point。在字符到整形数值的映射上,Unicode和其它编码方式诸如ASCII并没有区别。

但是,Unicode存在多种编码方式,而ASCII只有一种方式:


字符集


编码方式


ASCII


ASCII Encoding, e.g. A -> 65


Unicode


UTF-8, UTF-16, UTF-32, etc

那么为什么Unicode有这么多种编码方式呢?因为在不同情况下对操作的时间和空间要求是不一样的。

而在设计之初,Unicode估计所有的Code
Points能够被2的16次方,也就是65536来表示。这种编码方式就是UCS-2,它是最初的对于Unicode的16位编码方式。通过这种方式,每一个Code
Point都可以用一个16位的值进行表示,该表示被称为Code Unit。这种表示方式的优点在于,对Unicode字符串的索引操作都可以在常数时间内完成,因为所有的字符都是由16位,也就是2个比特表示。

因为这种编码方式的便利性,所以一些平台诸如Java,JavaScript都采用了它。因此,JavaScript的字符串每一个字符都是由2个比特表示的。

而随着Unicode字符集的扩展,65536已经满足不了需求了,目前Unicode字符集中字符的数量已经超过了2的20次方。因此,新增加的部分被组织到由17个2的16次方所组成的子范围内。(17
* 2^16 = 1114112,所以目前Unicode的Code Point范围是0-1114111)

第一个子范围,用来容纳原来UCS-2中的字符集,它也被称为Basic
Multilingual Plane(BMP)。剩下的16个子范围,被称为Supplementary
Planes。

为了表示更多的字符,UCS-2的继任者UTF-16,是这样设计的:

对于Code Point大于等于65536的字符,由一对16位的Code
Unit表示。对于Code Point小于65536的字符,还是只需要1个16位的Code
Unit表示。因此,UTF-16是一种变长编码方式,所以在对Code Point做indexing操作也不是常数时间了。它通常都需要从字符串的开始往后搜索。

对于JavaScript,字符串的length属性,charAt以及charCodeAt方法,都是在Code
Unit的基础上工作,而不是Code Point。因此,当JavaScript需要表示出于Supplementary
Plane中的Code Point时,它都会使用两个CodeUnit来表示,简而言之:

JavaScript字符串是由16位的Code
Unit组成的。

所以,当需要处理BMP以外的Code
Point时,会带来一些问题,因为你不能依赖于length属性,charAt以及charCodeAt方法了。这时候可以考虑使用一些成熟的第三方库。

总结:

  1. JavaScript的字符串由16比特的Code
    Unit组成,而不是由Unicode Code Point组成。
  2. 大于等于65536的Code
    Point在JavaScript中由两个Code
    Units组成,被称为Surrogate Pair。
  3. Surrogate Pair会影响到length,charAt,charCodeAt以及正则表达式中
    . 的工作方式。
  4. 处理Code Point超过65535的字符串时,考虑使用第三方的库并查阅它的文档。

Effective JavaScript String Encoding Item 7

时间: 2024-08-30 03:37:55

Effective JavaScript String Encoding Item 7的相关文章

Effective JavaScript Variable Scope Item 10 避免使用with

本系列作为Effective JavaScript的读书笔记. Item 9:避免使用with关键字 重点: 设计with关键字本来是为了让代码变简洁,但是却起到了相反的效果,比如: function f(x, y) { with (Math) { return min(round(x), sqrt(y)); // ambiguous references } } 以上的代码中,调用的min,round以及sqrt都是Math上的方法. 如果Math对象上没有以上指定的方法,那么会在with以外

Effective JavaScript Variable Scope Item 8-9 Globals and Locals

本系列作为Effective JavaScript的读书笔记. Item 8:少用全局对象 重点: 全局对象能够带来便利,但是有经验的程序员都会视图避免它.因为它会带来潜在的命名冲突的风险 全局变量是维系不同模块之间的纽带,模块之间只能通过全局变量来访问对方提供的功能 能使用局部变量的时候,绝不要使用全局变量 在browser中,this关键字会指向全局的window对象 两种用来改变全局对象的方式,通过var关键字声明以及给全局对象设置属性(通过this关键字) 通过全局对象进行针对当前运行环

Effective JavaScript Item 25 使用bind方法来得到一个固定了this指向的方法

本系列作为Effective JavaScript的读书笔记. 当需要将方法抽取出来作为回调函数使用的时候,常常会因为this的指向不明而发生错误,比如: var buffer = { entries: [], add: function(s) { this.entries.push(s); }, concat: function() { return this.entries.join(""); } }; 如果想利用其中的add作为回调函数对一组数据进行添加: var source

Effective JavaScript Item 23 永远不要修改arguments对象

本系列作为Effective JavaScript的读书笔记. arguments对象只是一个类似数组的对象,但是它并没有数组对象提供的方法,比如shift,push等.因此调用诸如:arguments.shift(),arguments.push()是错误的. 在Item 20和Item 21中,知道了函数对象上存在call和apply方法,那么是不是可以利用它们来让arguments也能够利用数组的方法呢: function callMethod(obj, method) { var shi

Effective JavaScript Item 40 避免继承标准类型

本系列作为Effective JavaScript的读书笔记. ECMAScript标准库不大,但是提供了一些重要的类型如Array,Function和Date.在一些场合下,你也许会考虑继承其中的某个类型来实现特定的功能,但是这种做法并不被鼓励. 比如为了操作一个目录,可以让目录类型继承Array类型如下: function Dir(path, entries) { this.path = path; for (var i = 0, n = entries.length; i < n; i++

Effective JavaScript Item 39 绝不要重用父类型中的属性名

本系列作为Effective JavaScript的读书笔记. 如果需要向Item 38中的Actor对象添加一个ID信息: function Actor(scene, x, y) { this.scene = scene; this.x = x; this.y = y; this.id = ++Actor.nextID; scene.register(this); } Actor.nextID = 0; 同时,也需要向Actor的子类型Alien中添加ID信息: function Alien(

Effective JavaScript Item 28 不要依赖函数的toString方法

本系列作为Effective JavaScript的读书笔记. 在JavaScript中,函数对象上存在一个toString方法,它能够方便地将函数的源代码转换返回成一个字符串对象. (function(x) { return x + 1; }).toString(); // "function (x) {\n return x + 1;\n}" toString方法不仅仅会让一些黑客找到攻击的方法,而且该方法也存在严重的限制. 首先,toString方法的实现方式并没有被ECMASc

Effective JavaScript Item 27 使用闭包而不是字符串来封装代码

本系列作为Effective JavaScript的读书笔记. 对于代码封装,在JavaScript中有两种方式可以办到.第一种就是使用function,第二种则是利用eval()函数,传入到该函数的字符串参数可以是一段代码. 当对使用哪种方式犹豫不决时,使用function.因为使用字符串的一个重要缺点是,传入的字符串并不是一个闭包,而function则可以代表一个闭包.关于闭包的特点,在Item 11中进行了描述. 下面是一段使用字符串来封装代码的例子: function repeat(n,

Effective JavaScript Item 19 使用高阶函数 (High-Order Function)

本系列作为Effective JavaScript的读书笔记. 不要被高阶函数这个名字给唬住了.实际上,高阶函数只是代表了两类函数: 接受其他函数作为参数的函数 返回值为函数的函数 有了这个定义,你也许就发现你已经使用过它们了,典型的就是对于一些事件的处理时传入的回调函数. 另外的一个典型使用场景就是Array类型的sort函数,它可以接受一个function作为排序时比较的判断依据: [3, 1, 4, 1, 5, 9].sort(function(x, y) { if (x < y) { r