JSON作为一种轻量的数据传输格式,越来越受到人们的青睐。下面是我仿照Prototype的一些实现。 JSONFilter:/^\/\*-secure-([\s\S]*)\*\/\s*$/, unfilterJSON:function(json,filter) { return json.replace((filter || dom.JSONFilter), function(a,b){ return 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*/' dom.unfilterJSON(text) // -> '{"name": "Violet", "occupation": "character", "age": 25}' 到时我们用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 ) return null; json = dom.unfilterJSON(json); if ( !sanitize || dom.isJSONText(json) ) { return window.JSON && window.JSON.parse ? window.JSON.parse( json ) : (new Function("return " + json))(); } else { throw "Invalid JSON: " + json; } } //http://www.21kaiyun.com var data =dom.evalJSON( '{ "name": "Violet", "occupation": "character" }'); data.name; //-> "Violet" 第四函数,将JSON对象变成文本。
// var a = [1,2,3,4,{aa:8}]; puts(dom.toJSON(a)) toJSON:function(obj){ if (window.JSON && window.JSON.stringify) { return JSON.stringify(obj) } if (typeof window.uneval == 'function') { return uneval(obj); } if (typeof obj == 'object') { if (!obj) { return 'null'; } var list = []; if (dom.is(obj,"Array")) { for (var i=0,n=obj.length;i <n;i++) { list.push(dom.toJSON(obj[i])); } return '[' + list.join(',') + ']'; } else { for (var prop in obj) { if(obj[has](prop)) list.push('"' + prop + '":' + dom.toJSON(obj[prop])); } return '{' + list.join(',') + '}'; } } else if (typeof obj == 'string') { return '"' + obj.replace(/(["'])/g, '\\$1') + '"'; } else { return new String(obj); } }, toJSON : function(obj) { if(is(window.JSON,"JSON")){ return JSON.stringify(obj) } function f(n) { 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; var meta = { '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\' }; function _char(c) { return meta[c] ? meta[c] :'\\u'+('0000'+(+(c.charCodeAt(0))).toString(16)).slice(-4); } function _string(s) { return '"' + s.replace(escapable, _char) + '"'; } if(is(obj,"Date")){ 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")){ return obj+'' }else if(is(obj,"String")){ return _string(obj) }else if(obj === null){ return "null" }else if(is(obj,"Array")){ return '[' + (dom.filter(obj,function(value){ return dom.toJSON(value) !== undefined; })).join(', ') + ']'; }else if(is(obj,"Object")){ var results = []; dom.each(obj,function(value,key){ value = dom.toJSON(value) if (!value) results.push(dom.toJSON(key) + ': ' + value); }); return '{' + results.join(', ') + '}'; }else { return undefined; } }, Is函数 目前最精确的判定方法(不包括自定义类型) //2010.6.1更新 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")){ array.forEach(fn,bind); }else{ for(var i=0,n=array.length;i<n;i++){ i in array && fn.call(bind,array[i],i,array) } } } //***************示例二,判定null var a = null alert(is(a,"Null")) //***************示例二,判定undefined var b alert(is(b,"Undefined")) 另一个变种,直接返回表示类型的字符串 var getType = function (obj) { var _toString = Object.prototype.toString,undefined; return obj === null? "Null": obj === undefined ? "Undefined": _toString.call(obj).slice(8,-1); }; 用法: var arr = [1,2,3,4] alert(getType(arr));//Array var nil = null alert(getType(nil))//Null var und ; alert(getType(und))//Undefined var spans = document.getElementsByTagName("span"); alert(getType(spans)) //HTMLCollection alert(getType(spans[0].childNodes))//NodeList //2010.7.20 function isA (thing, canon) { // special case for null and undefined if (thing == null || canon == null) { return thing === canon; } return Object.getPrototypeOf(Object(thing)) == Object.getPrototypeOf(Object(canon)); } function isBool (thing) { return isA(thing, true); } function isNumber (thing) { return isA(thing, 0) && isFinite(thing); } function isString (thing) { return isA(thing, ""); } |