■前置き
JavaScriptにおけるevalとは非常に強力である反面、危険でもある(正しくパースされていないJSONなど)。またscriptの実行速度を低下させたりもする。そんな訳で以下のようなコードが世界には存在する。
■json.js
// JavaScript Document
var json_parse = (function(){
//JSONをパースして、JavaScriptのデータ構造を生成する関数。
//これはシンプルな再帰下降パーサである
//グローバル変数を生成することを避けるため、
//この関数は他の関数の中で定義される
var at;
var ch;
var escapee = {
'"' : '"',
'\\': '\\',
'/' : '/',
b : 'b',
f : 'f',
n : 'n',
r : 'r',
t : 't'
};
var text;
var error = function(m){
throw{
name : 'SyntaxError',
message: m,
at : at,
text : text
};
};
var next = function(c){
if(c && c !== ch){
error("Expected '" + c + "' instead of '" + ch + "'");
}
ch = text.charAt(at);
at += 1;
return ch;
}
var number = function(){
var number, string = '';
if(ch === '-'){
string = '-';
next('-');
}
while(ch >= '0' && ch <= '9'){
string += ch;
next();
}
if(ch === '.'){
string += '.';
while(next() && ch >= '0' && ch <= '9'){
string += ch;
}
}
if(ch === 'e' || ch === 'E'){
string += ch;
next();
if(ch === '-' || ch === '+'){
string += ch;
next();
}
while(ch >= '0' && ch <= '9'){
string += ch;
next();
}
}
number += string;
if(isNaN(number)){
error("Bad number");
}
else{
return number;
}
};
var string = function(){
var hex, i, string = '';
var uffff;
if(ch === '"'){
while(next()){
if(ch === '"'){
next();
return string;
}
else if(ch === '\\'){
next();
if(ch === 'u'){
uffff = 0;
for(i=0; i<4; i+=1){
hex = parseInt(next(), 16);
if(!isFinite(hex)){
break;
}
uffff = uffff * 16 + hex;
}
string += String.fromCharCode(uffff);
}
else if(typeof escapee[ch] === 'string'){
string += escapee[ch];
}
else{
break;
}
}
else{
string += ch;
}
}
}
error("Bad string");
};
var white = function(){
while(ch && ch <= ' '){
next();
}
};
var word = function(){
switch(ch){
case 't':
next('t');
next('r');
next('u');
next('e');
return true;
case 'f':
next('f');
next('a');
next('l');
next('s');
next('e');
return false;
case 'n':
next('n');
next('u');
next('l');
next('l');
return null;
}
error("Unexpected '" + ch + "'");
};
var value;
var array = function(){
var array = [];
if(ch === '['){
next('[');
white();
if(ch === ']'){
next(']');
return array;
}
while(ch){
array.push(value());
white();
if(ch === ']'){
next(']');
return array;
}
next(',');
white();
}
}
error("Bad array");
};
var object = function(){
var key;
var object = {};
if(ch === '{'){
next('{');
white();
if(ch === '}'){
next('}');
return object;
}
while(ch){
key = string();
white();
next(':');
object[key] = value();
white();
if(ch === '}'){
next('}');
return object;
}
next(',');
white();
}
}
error("Bad object");
};
var value = function(){
white();
switch(ch){
case '{':
return object();
case '[':
return array();
case '"':
return string();
case '-':
return number();
default:
return (ch >= '0' && ch <= '9')? number() : word();
}
};
return function(source, reviver){
var result;
text = source;
at = 0;
ch = ' ';
result = value();
white();
if(ch){
error("Syntax error");
}
return typeof reviver === 'function' ?
function walk(holder, key){
var k;
var v;
var value = holder[key];
if(value && typeof value === 'object'){
for(k in value){
if(Object.hasOwnProperty.call(value, k)){
v = walk(value, k);
if(v !== undefined){
value[k] = v;
}
else{
delete value[k];
}
}
}
}
return reviver.call(holder, key, value);
}({'' : result}, '') : result;
};
})();
■あとがき
出展「Douglas Crockford著『JavaScript: The Good Parts』(オライリー・ジャパン発行,2008)」
所用の為に本屋さんに言ったのですが、あまりに奥が深いので買った本です。JavaScriptを極めたいなら是非とも読んでみる事をお勧めします。
参考