上一篇博客咱们说到了如何进行数字类型(如Short、Int、Long类型)如何在JavaScript中进行二进制转换,若是感兴趣的能够能够阅读本系列第二篇博客——WebSocket系列之JavaScript中数字数据如何转换为二进制数据。此次,咱们来讲下string类型的数据如何进行处理。
本文是WebSocket系列的第三篇,主要介绍string数据与二进制数据之间的转换方法,具体的内容以下:javascript
string这个类型,对于熟悉JavaScript的同窗应该都不陌生,它是属于JavaScript中基础数据类型的一种。不过,咱们今天要先介绍下DOMString
。java
DOMString 是一个UTF-16字符串。因为JavaScript已经使用了这样的字符串,因此DOMString 直接映射到 一个String。将null传递给接受DOMString的方法或参数时一般会把其转换成为“null”。
在WebSocket中进行string类型数据传输时,使用的其实也是DOMString
。不过,根据MDN中对DOMString
的介绍咱们能够了解到,大部分平常使用场景中,咱们能够认为DOMString
就是一个string类型。因此,咱们只须要了解此类型,使用时仍然当成string类型处理便可。git
既然上面提到了UTF-16,那么咱们就来简单介绍下UTF-16,以及后端经常使用的UTF-8这两种编码方式。
为何须要介绍编码类型呢?由于咱们在与后端进行字符串数据传递时,可能使用的编码方式不一样,这样就会致使双方获得不一样的数据。所以,咱们在进行string的二进制数据通讯时,不只仅须要将字符串转换成二进制,还须要协商一致的string编码。github
UTF-16 (16-bit Unicode Transformation Format) 是Unicode字符编码五层次模型的第三层:字符编码表(Character Encoding Form,也称为"storage format")的一种实现方式。即把Unicode字符集的抽象码位映射为16位长的整数(即码元)的序列,用于数据存储或传递。
Unicode字符的码位,须要1个或者2个16位长的码元来表示,所以这是一个变长表示。
UTF-16是JavaScript中的string编码类型。后端
UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,也是一种前缀码。它能够用来表示Unicode标准中的任何字元,且其编码中的第一个字节仍与ASCII兼容,这使得原来处理ASCII字元的软件无须或只须作少部分修改,便可继续使用。UTF-8使用一至四个字节为每一个字符编码(2003年11月从新规范)。
UTF-8是不少语言使用的通用编码类型,在后端应用中很是常见。数组
在Github上有转换库GitHub - dcodeIO/utfx: A compact library to encode, decode and convert UTF8 / UTF16 in JavaScript.,经过这个库,能够将字符串在UTF-8编码和UTF-16编码中进行转换。该库的具体原理和内容以及两种编码方式的详细内容说明将会在以后的博客中进行讲解。咱们下面简单的介绍下它是使用方式:函数
import utfx from './util/utfx'; let str = 'abcdefg'; let result = []; function stringSource(s) { let i = 0; return function () { return i < s.length ? s.charCodeAt(i++) : null; }; } utfx.encodeUTF16toUTF8(stringSource(str), function (b) { result.push(b); }.bind(this));
同理,该类库提供了其余的方法:post
decodeUTF8toUTF16
,将UTF-8的string数据转换为UTF-16的string数据。calculateUTF16asUTF8
,计算UTF-16编码的string类型类型转换为UTF-8后所占Byte长度。了解了JavaScript中string类型的编码和在UTF-8和UTF-16之间转换编码的方式,下面咱们来看下如何将string类型转换为二进制数据。
首先,咱们假定与后端交互时使用的编码方式为UTF-8,这样可以知足更多的使用场景。若是仍然使用UTF-16的话,则直接忽略转换编码的逻辑便可。
简单介绍下实现思路:咱们获得一个须要转换的字符串后,先知道其长度后,初始化ArrayBuffer中相关参数,将数据放入ArrayBuffer中便可。咱们将上面的示例稍做改动:this
import utfx from './util/utfx'; function stringSource(s) { var i = 0; return function () { return i < s.length ? s.charCodeAt(i++) : null; }; } let str = 'abcdefg'; let strCodes = stringSource(str); let length = utfx.calculateUTF16asUTF8(strCodes)[1]; let buffer = new ArrayBuffer(length + 4); // 初始化长度为UTF8编码后字符串长度+4个Byte的二进制缓冲区 let view = new DataView(buffer); let offset = 4; view.setUint32(0, length); // 将长度放置在字符串的头部 utfx.encodeUTF16toUTF8(stringSource(str), function (b) { view.setUint8(offset++, b); }.bind(this));
经过上面的示例,咱们就已经将一个二进制数据根据UTF-8编码后放入了ArrayBuffer中,同时,将其长度做为一个Unsigned Int类型存储在了二进制头部4个Byte的位置。编码
知道了如何将string类型转换为二进制数据,下面咱们看下如何将整个数据从二进制中读取,转换回string类型。
根据上面转换为二进制的过程,咱们不难想到相关的二进制转string类型方法。具体示例以下:
import utfx from './util/utfx'; let str = 'abcdefg'; function stringSource(s) { var i = 0; return function () { return i < s.length ? s.charCodeAt(i++) : null; }; } let strCodes = stringSource(str); let length = utfx.calculateUTF16asUTF8(strCodes)[1]; let buffer = new ArrayBuffer(length + 4); // 初始化长度为UTF8编码后字符串长度+4个Byte的二进制缓冲区 let view = new DataView(buffer); let offset = 4; // 字符串转换二进制过程 view.setUint32(0, length); // 将长度放置在字符串的 utfx.encodeUTF16toUTF8(stringSource(str), function (b) { view.setUint8(offset++, b); }.bind(this)); // 二进制转换字符串过程 let Strlength = view.getUint32(0); offset = 4; let result = []; // Unicode编码字符 let end = offset + Strlength; utfx.decodeUTF8toUTF16(function () { return offset < end ? view.getUint8(offset++) : null; // 返回null时会退出此转换函数 }.bind(this), (char) => { console.log(char) result.push(char); }); let strResult = result.reduce((prev, next)=>{ return prev + String.fromCharCode(next); }, '');
经过上面的示例咱们能够知道,咱们只须要在前面4个Byte中将字符串长度读取出来,而后再从第4个Byte(从0开始算)的位置开始读取指定长度的字符串字符编码便可。最后,咱们获得了一个Unicode码数组,只须要fromCharCode
方法便可将其转换为字符串。
经过使用ArrayBuffer和DataView,咱们可以在string数据和二进制数据中进行互相转换。有了string类型转换的相关基础,读者就可以在以后的WebSocket进行二进制数据传递时理解相关的内容和处理逻辑。下一篇WebSocket系列相关的博客,将会介绍如何经过WebSocket来向后端传递二进制数据,以及如何处理经过WebSocket收到的二进制数据。有兴趣的同窗能够继续关注。