シリアライザ(h5.u.obj.serialize(),deserialize())の出力フォーマット
hifiveが提供するシリアライザ・デシリアライザ(h5.u.obj.serialize()/deserialize())の仕様を説明します。
概要
データを、型情報を付与した文字列に変換します。判定可能な型は、以下のとおりです。
string | 文字列 |
number | 数値 |
boolean | 真偽値 |
array | 配列 |
object | プレーンオブジェクト |
Date | 日付 |
RegExp | 正規表現 |
undefined | (undefined値) |
null | (null値) |
NaN | (NaN値) |
Infinity | (Infinity値) |
-Infinity | (-Infinity値) |
stringのラッパークラス | new String()で生成したオブジェクト |
numberのラッパークラス | new Number()で生成したオブジェクト |
booleanのラッパークラス | new Boolean()で生成したオブジェクト |
シリアライズ
シリアライズは、バージョンなどの情報を含むヘッダを付加します。ヘッダの後に、型情報文字、文字列化したデータが続きます。
- ヘッダ情報 + | + 型情報文字(1byte) + 文字列化したデータ
ヘッダ
現在の仕様におけるヘッダは"2"です。
文字列化
オブジェクトを、1byteの型情報文字+文字列化したデータに変換します。
型 | 型情報文字 | 値 | 文字列化 | 備考 |
---|---|---|---|---|
string | s | hello | shello | |
number | n | 1, -1.23 | n1, n-1.23 | |
boolean | b | true, false | b1, b0 | true=1, false=0に変換します |
Date | d | new Date() | d1331698922654 | getTime()の値を使います |
RegExp | r | /a*/g | r/a*/g | |
undefined | u | undefined | u | |
null | l | null | l | |
NaN | x | NaN | x | |
Infinity | i | Infinity | i | |
-Infinity | I | -Infinity | I | |
Array | a | [1,'hello'] | a["n1","shello"] | |
Object | o | { a: 'A', b: 2 } | o{"a":"sA","b":"n2"} | |
Stringのラッパークラス | S | new String('hello') | Shello | |
Numberのラッパークラス | N | new Number(123), new Number(NaN) | N123, Nx | |
Booleanのラッパークラス | B | new Boolean(true), new Boolean(false) | B1, B0 |
[配列またはオブジェクト]中の[配列またはオブジェクト]は、'"'と'\'をエスケープして表現します。
例
[[1 ,2, 3], 4, 5] → a["a[\"n1\",\"n2\",\"n3\"]","n4","n5"]
{ary:[1, [2, 3]], obj:{a:'A'}} → o{"ary":"a[\"n1\",\"a[\\\"n2\\\",\\\"n3\\\"]\"]","obj":"o{\"a\":\"sA\"}"}
serialize()メソッドが返す値は、次のようになります。
- serialize(123) → 2|n123
- serialize('null') → 2|snull
- serialize(null) → 2|l
- erialize([1,NaN,Infinity,'4']) →2|a["n1","x","i","s4"]
オブジェクト
オブジェクトはプレーンオブジェクトとしてシリアライズします。渡されたオブジェクトがプレーンオブジェクトでない場合、そのprototypeやconstructorは無視されます。デシリアライズで復元されたオブジェクトは必ずプレーンオブジェクトです。
連想配列
配列は連想配列も含めてシリアライズします。連想配列部分はオブジェクトと同様の方法で文字列化し、'@'を文字列化した文字にの先頭に付け、配列の最後の要素に加えます。'@'は連想配列としてマッピングされたオブジェクトを表す指定子として扱います。
a['a'] = 'A';
このような配列 a をシリアライズすると次のようになります。
- 2|a["n0","1","@{\"a\":\"sA\"}"]
デシリアライズの際に、'@'指定子のある要素を、"連想配列としてマッピングするオブジェクト"として評価します。
循環参照
循環参照を含む配列またはオブジェクトはシリアライズできません。エラーが発生します。
同一インスタンスの扱い
配列またはオブジェクトが内部に同一インスタンスを持つ場合、シリアライザはそれらを別インスタンスとして扱います。
a[0] = a[1] = [];
var b = h5.u.obj.deserialize(h5.u.obj.serialize(a));
// a[0]とa[1]は同一インスタンスだが、b[0]とb[1]は同一インスタンスではない。
a[0][0] = 1 // [Array[1], Array[1]]
b[0][0] = 1 // [Array[1], Array[0]]
配列中のundefined
このような配列の場合、a[1]とa[2]は共にundefinedですが、a.hasOwnProperty(1)がtrueなのに対し、a.hasOwnProperty(2)はfalseです。このような場合も区別してシリアライズします。上記の a をシリアライズすると以下のようになります。
- 2|a["n0","u","_","n3]
"u"は値としてのundefinedを表しますが、"_"は配列中の未定義によるundefinedを表します。
a[5] = 5;
このような a をシリアライズすると、以下のようになります。
- 2|a["_","_","_","_","_","n5"]
関数型
関数型のオブジェクトはシリアライズできません。エラーが発生します。配列中に関数があった場合、undefinedとしてシリアライズします。オブジェクトまたは連想配列中に関数があった場合は無視されます。
a['func'] = function(){};
var b = [function(){}, , 2];
b['func'] = function(){};
b['num'] = 1;
var c = { func: function(){} }
このような a b c はそれぞれ以下のようにシリアライズされます。
- 2|a[]
- 2|a["u","_","n2","@{\"num\":\"n1\"}"]
- 2|o{}