カスタム JSON パーサー/文字列化子をJSON.stringify
およびに提供できJSON.parse
ます。
var serialized = JSON.stringify(obj, /*func*/replacer);
var deserialized = JSON.parse(serialized, /*func*/reviver);
カスタム リバイバーに加えて、toJSON
シリアル化されるオブジェクトにメソッドを定義することもできます。このメソッドは引数を 1 つ受け取ります。配列内のキーの名前のインデックス、オブジェクト内のプロパティ名 (該当する場合) です。
// Examples of a serializing a function
var dummyFunction = function() {return 'hey';};
Function.prototype.toJSON = function(key) {
'use strict';
return this.toString();
};
JSON.stringify(dummyFunction);
// Method 2:
var replacer = function(/*string*/key, /*any*/value, /*boolean*/pretty_print) {
if (typeof value == 'function') return value.toString();
return value;
};
JSON.stringify(dummyFunction, replacer);
// >>> "function () {\n return \"hey\";\n}"
// Result of the previous, stored in a variable
var result = '"function () {\\n return \\"hey\\";\\n}"';
// Reviver example
// Note: Just an example. Do not use it without modification in production code,
// Because the pattern can easily be misguided: "function(){}alert('Evil');x={}"
// Even if you do not mind, at least add a try-catch block inside
// `if (func)`, so that a malformed function does not break the reviver
JSON.parse(result, function(/*string*/key, /*string*/value) {
var func = /^\s*function\s*\(([^)]*)\)\s\{([\S\s]*)}$/.exec(value);
if (func) {
// Note: Function( .. ) is equivalent to new Function( .. )
var args = func[1].match(/[^,\s]+/g); // <-- Parameters
// Function body:
if (args === null) args = [func[2]];
else args.unshift(func[2]);
return Function.apply(null, args);
}
return value;
});
ネイティブ解析とリバイバーを使用した解析の JSPerf 比較を次に示します: http://jsperf.com/json-reviver。特別なことを何もしないカスタム リバイバーは 2 倍遅く、高価な機能を備えたリバイバーは大幅に遅いことがわかります。
ただし、最後の方法を、ネイティブ JSON と「手動変換」を使用するより弱い方法と比較すると、違いは無視されているように見えます。
注: 単一の値のみがベンチマークされます。可能性のあるすべてのケースを表す 1 つのベンチマークを作成することは不可能であるため、独自の (特定の) ケース用のカスタム ベンチマークを必ず作成してください。
の影響をチェックするJSPerf テスト ケースを作成しました.toJSON
。Date
ノイズを分離するために、オブジェクトに基づいてテスト ケースを作成しました。複数の関数呼び出しを持つカスタム関数は、ネイティブ関数よりもわずか 2 倍遅くなりますDate.prototype.toJSON
。