XENON基于JSON變種
更新時間:2010年07月27日 08:29:43 作者:
JSON已經(jīng)成為了現(xiàn)在互聯(lián)網(wǎng)上輕量級數(shù)據(jù)傳輸?shù)氖聦崢?biāo)準(zhǔn),現(xiàn)在已經(jīng)很少聽說哪個流行的web API不支持JSON了,而很多內(nèi)部或者專用的應(yīng)用程序也都在使用JSON來傳遞數(shù)據(jù)。
但是在用JSON的過程中,我遇到了一個問題——這個問題想必是大家多少都遇到過,那就是:JSON沒有定義日期和時間的傳遞方式。
盡管在今年3月的一次更新中,json2.js已經(jīng)增加了對Date函數(shù)和ISO-8601式的日期/時間格式,但各種常用的開發(fā)工具中對日期的支持還是五花八門、千奇百怪的,完全沒有統(tǒng)一。
而且,除了日期/時間以外,個別時候我們還需要一些類或者函數(shù)的支持,而這些都是不被JSON所支持的。
可能有的人看到這里要問了:既然JSON不支持,那為什么不去用別的數(shù)據(jù)描述/傳輸方式呢?
原因是JSON本身就是JavaScript(其參考標(biāo)準(zhǔn)為ECMAScript)的功能子集,任何稍懂JavaScript的人都可以輕松地利用JSON。
解析JSON最簡單的辦法是直接使用eval函數(shù)將其作為JavaScript代碼來執(zhí)行,而JSON常常被用在互聯(lián)網(wǎng)上的不同應(yīng)用之間傳遞,所以直接將收到的JSON內(nèi)容傳入eval函數(shù)是具有很大的風(fēng)險的,因此在RFC文檔中嚴(yán)格規(guī)定了JSON的格式,并且給出了檢驗其安全性的辦法。
而這個檢驗辦法就禁止了函數(shù)的運行。
總而言之,因為JSON在使用上“偶爾”會有些不方便,所以我就開始動腦筋擴(kuò)展JSON了。
在參考了RFC-4627、json2.js以及一些常見的JavaScript語法著色器以后,我發(fā)現(xiàn):雖然json2.js已經(jīng)有了對日期/時間的支持,但它所采用的語法分析的模式,這就意味著如果不是對語法分析有一定的了解,是很難對它進(jìn)行擴(kuò)展的;即使我稍微研習(xí)過一些語法分析的知識,想要擴(kuò)展它也并非很容易的事情,更別談日后的維護(hù)了。
所以我決定用RFC-4627中建議的較為簡單的正則表達(dá)式過濾法。
這個擴(kuò)展的基本實現(xiàn)是這樣的:
function Xenon(){}
var protoXenon = Xenon.prototype;
protoXenon.xeval = function(s){
var al = [], vl = [], ol = {};
function $(i, v){
// i = parseInt(i);
// return ol[i] || (ol[i] = v);
return ol.propertyIsEnumerable(i) ? ol[i] : (ol[i] = v);
}
for(var n in this)
if(this.propertyIsEnumerable(n) && typeof this[n] == 'function')
al.push(n), vl.push(this[n]);
return eval('0,function(' + al + '){return ' + s + ';}').apply(this, vl);
};
protoXenon.safeXeval = function(s){
var T = this;
return (!/[^\),:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
s.replace(/"(\\.|[^"\\])*"/g, '')
.replace(/([^\s:\[,\(]+?)\(/g,function($0, $1){
// return T.propertyIsEnumerable($1) ? '' : $1 + '(';
return T.propertyIsEnumerable($1) ? '' : '@';
})) || null) &&
this.xeval(s);
};
基本用法就是創(chuàng)建一個xenon對象,為其設(shè)置新的成員以啟用擴(kuò)展函數(shù)。
可以把擴(kuò)展函數(shù)直接添加到xenon對象上,也可以在全局作用域中聲明函數(shù)再在xenon對象上設(shè)置非函數(shù)類型的成員值。
例子:
var xenon = new Xenon();
xenon.Array = 0;
xenon.$ = 0;
xenon.date = function(s){return new Date(s);};
var o = xenon.safeXeval('{"list":Array(3,6,9),"created":$(1,date("Tue Jul 27 02:48:03 UTC+0800 2010")),"modified":$(1)}');
print(o.list);
print(o.created);
print(o.modified == o.created);
注:這個例子并不能直接作為JScript.NET代碼執(zhí)行,若要在JScript.NET中使用則必須將字符串"unsafe"作為第二個參數(shù)傳遞給eval函數(shù)。
注2:function關(guān)鍵字前增加“0,”是為了兼容于IE所使用的JScript引擎——當(dāng)前的非CLI版本JScript引擎在其eval的實現(xiàn)中并不能正確地理解包圍著函數(shù)定義的圓括號的意義,會因此引發(fā)語法錯誤。
在這個例子中使用了三個函數(shù)擴(kuò)展:Array為全局作用域中的JavaScript內(nèi)置函數(shù);$是我在XENON中實現(xiàn)的內(nèi)置功能,可以在多處引用同一個對象;而date則是對Date構(gòu)造器的包裝。
在XENON的實現(xiàn)中我沒有讓它支持new操作符創(chuàng)建新對象,我沒發(fā)現(xiàn)有要用new而不能直接用擴(kuò)展函數(shù)的理由。
關(guān)于名字:起初打算叫做xJson,但是后來想想覺得有點遜,改作XEON(eXtensible ECMAScript Object Notation)之后又發(fā)現(xiàn)好像是Intel的注冊商標(biāo),所以在中間多加了個N變成了XENON(eXtensible Native ECMAScript Object Notation)。查了下字典,是個化學(xué)元素的名字……就這么湊合用吧。
關(guān)于安全性:在設(shè)計檢驗方法的過程中我盡可能測試了我所想得到的字符組合,力求避免注入問題。但是由于缺乏實踐檢驗,我也不擅長語法分析之類的事情,所以可能并不是絕對安全。如果誰發(fā)現(xiàn)了其中的安全漏洞,可以通知我來改進(jìn)它。
以后有時間我會做一個簡單的從ECMAScript對象向XENON轉(zhuǎn)換的函數(shù);如果真的有很充裕的時間,也許我還會實現(xiàn)包含類名和構(gòu)造器的轉(zhuǎn)換過程。
盡管在今年3月的一次更新中,json2.js已經(jīng)增加了對Date函數(shù)和ISO-8601式的日期/時間格式,但各種常用的開發(fā)工具中對日期的支持還是五花八門、千奇百怪的,完全沒有統(tǒng)一。
而且,除了日期/時間以外,個別時候我們還需要一些類或者函數(shù)的支持,而這些都是不被JSON所支持的。
可能有的人看到這里要問了:既然JSON不支持,那為什么不去用別的數(shù)據(jù)描述/傳輸方式呢?
原因是JSON本身就是JavaScript(其參考標(biāo)準(zhǔn)為ECMAScript)的功能子集,任何稍懂JavaScript的人都可以輕松地利用JSON。
解析JSON最簡單的辦法是直接使用eval函數(shù)將其作為JavaScript代碼來執(zhí)行,而JSON常常被用在互聯(lián)網(wǎng)上的不同應(yīng)用之間傳遞,所以直接將收到的JSON內(nèi)容傳入eval函數(shù)是具有很大的風(fēng)險的,因此在RFC文檔中嚴(yán)格規(guī)定了JSON的格式,并且給出了檢驗其安全性的辦法。
而這個檢驗辦法就禁止了函數(shù)的運行。
總而言之,因為JSON在使用上“偶爾”會有些不方便,所以我就開始動腦筋擴(kuò)展JSON了。
在參考了RFC-4627、json2.js以及一些常見的JavaScript語法著色器以后,我發(fā)現(xiàn):雖然json2.js已經(jīng)有了對日期/時間的支持,但它所采用的語法分析的模式,這就意味著如果不是對語法分析有一定的了解,是很難對它進(jìn)行擴(kuò)展的;即使我稍微研習(xí)過一些語法分析的知識,想要擴(kuò)展它也并非很容易的事情,更別談日后的維護(hù)了。
所以我決定用RFC-4627中建議的較為簡單的正則表達(dá)式過濾法。
這個擴(kuò)展的基本實現(xiàn)是這樣的:
復(fù)制代碼 代碼如下:
function Xenon(){}
var protoXenon = Xenon.prototype;
protoXenon.xeval = function(s){
var al = [], vl = [], ol = {};
function $(i, v){
// i = parseInt(i);
// return ol[i] || (ol[i] = v);
return ol.propertyIsEnumerable(i) ? ol[i] : (ol[i] = v);
}
for(var n in this)
if(this.propertyIsEnumerable(n) && typeof this[n] == 'function')
al.push(n), vl.push(this[n]);
return eval('0,function(' + al + '){return ' + s + ';}').apply(this, vl);
};
protoXenon.safeXeval = function(s){
var T = this;
return (!/[^\),:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/.test(
s.replace(/"(\\.|[^"\\])*"/g, '')
.replace(/([^\s:\[,\(]+?)\(/g,function($0, $1){
// return T.propertyIsEnumerable($1) ? '' : $1 + '(';
return T.propertyIsEnumerable($1) ? '' : '@';
})) || null) &&
this.xeval(s);
};
基本用法就是創(chuàng)建一個xenon對象,為其設(shè)置新的成員以啟用擴(kuò)展函數(shù)。
可以把擴(kuò)展函數(shù)直接添加到xenon對象上,也可以在全局作用域中聲明函數(shù)再在xenon對象上設(shè)置非函數(shù)類型的成員值。
例子:
復(fù)制代碼 代碼如下:
var xenon = new Xenon();
xenon.Array = 0;
xenon.$ = 0;
xenon.date = function(s){return new Date(s);};
var o = xenon.safeXeval('{"list":Array(3,6,9),"created":$(1,date("Tue Jul 27 02:48:03 UTC+0800 2010")),"modified":$(1)}');
print(o.list);
print(o.created);
print(o.modified == o.created);
注:這個例子并不能直接作為JScript.NET代碼執(zhí)行,若要在JScript.NET中使用則必須將字符串"unsafe"作為第二個參數(shù)傳遞給eval函數(shù)。
注2:function關(guān)鍵字前增加“0,”是為了兼容于IE所使用的JScript引擎——當(dāng)前的非CLI版本JScript引擎在其eval的實現(xiàn)中并不能正確地理解包圍著函數(shù)定義的圓括號的意義,會因此引發(fā)語法錯誤。
在這個例子中使用了三個函數(shù)擴(kuò)展:Array為全局作用域中的JavaScript內(nèi)置函數(shù);$是我在XENON中實現(xiàn)的內(nèi)置功能,可以在多處引用同一個對象;而date則是對Date構(gòu)造器的包裝。
在XENON的實現(xiàn)中我沒有讓它支持new操作符創(chuàng)建新對象,我沒發(fā)現(xiàn)有要用new而不能直接用擴(kuò)展函數(shù)的理由。
關(guān)于名字:起初打算叫做xJson,但是后來想想覺得有點遜,改作XEON(eXtensible ECMAScript Object Notation)之后又發(fā)現(xiàn)好像是Intel的注冊商標(biāo),所以在中間多加了個N變成了XENON(eXtensible Native ECMAScript Object Notation)。查了下字典,是個化學(xué)元素的名字……就這么湊合用吧。
關(guān)于安全性:在設(shè)計檢驗方法的過程中我盡可能測試了我所想得到的字符組合,力求避免注入問題。但是由于缺乏實踐檢驗,我也不擅長語法分析之類的事情,所以可能并不是絕對安全。如果誰發(fā)現(xiàn)了其中的安全漏洞,可以通知我來改進(jìn)它。
以后有時間我會做一個簡單的從ECMAScript對象向XENON轉(zhuǎn)換的函數(shù);如果真的有很充裕的時間,也許我還會實現(xiàn)包含類名和構(gòu)造器的轉(zhuǎn)換過程。
相關(guān)文章
Json對象與Json字符串互轉(zhuǎn)(4種轉(zhuǎn)換方式)
Json字符與Json對象的相互轉(zhuǎn)換方式有很多,接下來將為大家一一介紹下,感興趣的朋友可以參考下哈,希望可以幫助到你2013-03-03JQuery用$.ajax或$.getJSON跨域獲取JSON數(shù)據(jù)的實現(xiàn)代碼
這篇文章主要介紹了JQuery用$.ajax或$.getJSON跨域獲取JSON數(shù)據(jù)的實現(xiàn)代碼,需要的朋友可以參考下2017-09-09