JSON作为一种轻量的数据传输格式,越来越受到人们的青睐。下面是我仿照Prototype的一些实现。
JSONFilter:/^\/\*-secure-([\s\S]*)\*\/\s*$/, |
unfilterJSON: function (json,filter) { |
return json.replace((filter || dom.JSONFilter), function (a,b){ |
JSONFilter完全抄自Prototype,因为后台基本上只会传输两种格式的东西给我们——文本(xmlhttp.responseText)与XML(xmlhttp.responseXML)。如果要json,我们可以eval一下,或者使用现代浏览器提供的JSON.parse方法。但问题就出在eval中,很容易出现XSS攻击。如果文本是注释就可以避免这问题,在Prototype中还检察一下请求的来源。对于自家的网站的请求,我们完全可以在请求前处理一下,让它变成如下格式:
var text = '/*-secure-\n{"name": "Violet", "occupation": "character", "age": 25}\n*/' |
到时我们用unfilterJSON函数提取合法的字段来eval就没问题了。
第二个函数,判断字符串是否符合JSON的格式。JSON是有固定的格式,要求键必须被双引号括起来。下面的函数提取自json2:
isJSONText: function (json){ |
return /^[\],:{}\s]*$/.test(json.replace(/\\(?:[ "\\\/bfnrt]|u[0-9a-fA-F]{4})/g, " @") |
.replace(/ "[^" \\\n\r]* "|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, " ]") |
.replace(/(?:^|:|,)(?:\s*\[)+/g, "" )); |
第三个函数,将符合JSON的格式的文本变成JSON对象。第二参数用于指明此文本是否安全(如,是否同源请求)。如果能用原生对象的parse方法就用原生的,否则动态解析它。之所以不用eval,是因为ecma那帮人头脑发热,想禁掉它。
evalJSON: function ( json ,sanitize) { |
if ( !is(json, "String" ) || !json ) |
json = dom.unfilterJSON(json); |
if ( !sanitize || dom.isJSONText(json) ) { |
return window.JSON && window.JSON.parse ? |
window.JSON.parse( json ) : ( new Function( "return " + json))(); |
throw "Invalid JSON: " + json; |
var data =dom.evalJSON( '{ "name": "Violet", "occupation": "character" }' ); |
第四函数,将JSON对象变成文本。
if (window.JSON && window.JSON.stringify) { |
return JSON.stringify(obj) |
if ( typeof window.uneval == 'function' ) { |
if ( typeof obj == 'object' ) { |
if (dom.is(obj, "Array" )) { |
for ( var i=0,n=obj.length;i <n;i++) { |
list.push(dom.toJSON(obj[i])); |
return '[' + list.join( ',' ) + ']' ; |
list.push( '"' + prop + '":' + dom.toJSON(obj[prop])); |
return '{' + list.join( ',' ) + '}' ; |
} else if ( typeof obj == 'string' ) { |
return '"' + obj.replace(/([" '])/g, ' \\$1 ') + ' "'; |
if (is(window.JSON, "JSON" )){ |
return JSON.stringify(obj) |
return n < 10 ? '0' + n : n; |
var escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; |
return meta[c] ? meta[c] : '\\u' +( '0000' +(+(c.charCodeAt(0))).toString(16)).slice(-4); |
return '"' + s.replace(escapable, _char) + '"' ; |
return '"' + obj.getUTCFullYear() + '-' + |
f(obj.getUTCMonth() + 1) + '-' + |
f(obj.getUTCDate()) + 'T' + |
f(obj.getUTCHours()) + ':' + |
f(obj.getUTCMinutes()) + ':' + |
f(obj.getUTCSeconds()) + 'Z"' ; |
} else if (is(obj, "Number" )){ |
return isFinite(obj) ? obj+ '' : 'null' ; |
} else if (is(obj, "Boolean" )){ |
} else if (is(obj, "String" )){ |
} else if (is(obj, "Array" )){ |
return '[' + (dom.filter(obj, function (value){ |
return dom.toJSON(value) !== undefined; |
} else if (is(obj, "Object" )){ |
dom.each(obj, function (value,key){ |
value = dom.toJSON(value) |
results.push(dom.toJSON(key) + ': ' + value); |
return '{' + results.join( ', ' ) + '}' ; |
Is函数
目前最精确的判定方法(不包括自定义类型)
var is = function (obj,type) { |
return (type === "Null" && obj === null ) || |
(type === "Undefined" && obj === void 0 ) || |
(type === "Number" && isFinite(obj)) || |
Object.prototype.toString.call(obj).slice(8,-1) === type; |
用法如下:
var forEach = function (array,fn,bind){ |
if (is(array, "Array" ) && is(Array.forEach, "Function" )){ |
for ( var i=0,n=array.length;i<n;i++){ |
i in array && fn.call(bind,array[i],i,array) |
另一个变种,直接返回表示类型的字符串
var getType = function (obj) { |
var _toString = Object.prototype.toString,undefined; |
return obj === null ? "Null" : |
obj === undefined ? "Undefined" : |
_toString.call(obj).slice(8,-1); |
用法:
var spans = document.getElementsByTagName( "span" ); |
alert(getType(spans[0].childNodes)) |
function isA (thing, canon) { |
if (thing == null || canon == null ) { |
return Object.getPrototypeOf(Object(thing)) == Object.getPrototypeOf(Object(canon)); |
function isBool (thing) { |
function isNumber (thing) { |
return isA(thing, 0) && isFinite(thing); |
function isString (thing) { |