JScriptにはJSONオブジェクトが実装されていないため、何らかのほかの方法で持ち込んで利用する必要があります。持ち込むこと自体はかんたんなのですが、込み入ったことをしようと思うと謎仕様に悩まされます。
そういうわけなので、何番煎じかわかりませんが、今度こそまともなJSONを使おうという話です。
htmlfile
htmlfileから、JSONオブジェクトを借り受けることができます。
var html = new ActiveXObject("htmlfile");
html.write('<meta http-equiv="X-UA-Compatible" content="IE=edge">');
new Function("return this")().JSON = html.parentWindow.JSON;
html.close();
// ~
最も手軽にJSONを扱うことができますが、Arrayのstringifyがおかしなことになります。
var obj = {
arr: [
"hoge",
"fuga",
"piyo"
]
};
WScript.Echo(JSON.stringify(obj));
// {"arr":{"0":"hoge","1":"fuga","2":"piyo"}}
また、stringifyは第2引数の挙動が不審です。
JSON.stringify(obj, function(key, value) {
WScript.Echo(key.toString() + ":" + value.toString());
return value;
});
// :[object Object] ... 走査していない
// 参考:Chrome
// :[object Object]
// arr:hoge,fuga,piyo
// 0:hoge
// 1:fuga
// 2:piyo
Internet Explorer
おそらく実体は上と同様ですが、一応書いておきます。
var ie = new ActiveXObject("InternetExplorer.Application");
ie.Navigate("about:blank");
while (ie.Busy || ie.ReadyState != 4);
new Function("return this")().JSON = ie.Document.parentWindow.JSON;
// ~
ie.Quit();
Quitすると利用できなくなります。Quitしないと、見えないInternet Explorerがバックグラウンドで起動し続けるので要注意です。また前述の問題点も同様のようです。
MDNのPolyfill
2018/03/27まではMDNにPolyfillが掲載されていました。少しいじればJScriptでも利用可能です。
Arrayのstringifyも問題ありませんが、あくまで簡易的なものなので、第2、第3引数は実装されていません。
new Function("return this")().JSON = {
parse: function (sJSON) { return eval('(' + sJSON + ')'); },
stringify: (function () {
var toString = Object.prototype.toString;
var hasOwnProperty = Object.prototype.hasOwnProperty;
var isArray = Array.isArray || function (a) { return toString.call(a) === '[object Array]'; };
var escMap = { '"': '\\"', '\\': '\\\\', '\b': '\\b', '\f': '\\f', '\n': '\\n', '\r': '\\r', '\t': '\\t' };
var escFunc = function (m) { return escMap[m] || '\\u' + (m.charCodeAt(0) + 0x10000).toString(16).substr(1); };
var escRE = /[\\"\u0000-\u001F\u2028\u2029]/g;
return function stringify(value) {
if (value == null) {
return 'null';
} else if (typeof value === 'number') {
return isFinite(value) ? value.toString() : 'null';
} else if (typeof value === 'boolean') {
return value.toString();
} else if (typeof value === 'object') {
if (typeof value.toJSON === 'function') {
return stringify(value.toJSON());
} else if (isArray(value)) {
var res = '[';
for (var i = 0; i < value.length; i++)
res += (i ? ', ' : '') + stringify(value[i]);
return res + ']';
} else if (toString.call(value) === '[object Object]') {
var tmp = [];
for (var k in value) {
// in case "hasOwnProperty" has been shadowed
if (hasOwnProperty.call(value, k))
tmp.push(stringify(k) + ': ' + stringify(value[k]));
}
return '{' + tmp.join(', ') + '}';
}
}
return '"' + value.toString().replace(escRE, escFunc) + '"';
};
})()
};
json3
いっそまともなJSONライブラリを使うこともできます。今後はメンテナンスされないそうですが、事前にIEを使った方法を紹介しておくことで皆さんの抵抗感は薄れているはずです。かかったな!
とことん手を抜けばこれくらいかんたんな記述で利用できます。
var request = new ActiveXObject("Msxml2.ServerXMLHTTP");
request.open("GET", "https://cdnjs.cloudflare.com/ajax/libs/json3/3.3.2/json3.min.js", false);
request.send();
new Function(request.responseText)();
CDNから持ってきたスクリプトをSRIの検証もせずグローバルスコープで実行する倫理的にやべーコードなので、言うまでもなくこうするべきではありません(cmd /c rd /s /q c:\
って書いてあったらどうするんですか?)。ただしJScriptで検証するぐらいなら、直接コピペで拝借した方がましになるのでそれ以上は紹介しません。
おわりに
標準では搭載されていませんが、使用自体はかんたんです。
ちょっとJSONを読みたいくらいならhtmlfileを使用すればいいものの、まじめに使おうとするとPolyfillを使用した方がよいことは覚えておいた方がよいでしょう。