JSON.parse和JSON.stringify这两个浏览器自带(IE6/7除外)的方法平常我们经常用到,但是一般都只是用到了他们的第一个参数,比如字符串转对象:JSON.parse(‘{}‘) 对象转字符串:JSON.stringify({})
今天特意看了下这两个方法的定义,第二个可选参数也是非常有用。
1. JSON.parse(text[, reviver])
text : 要被解析成JSON对象的字符串
reviver : 如果是一个函数,则规定了原始值如何被解析改造,在被返回之前。 function(key, value){ return value;}
如果指定了 reviver 函数,则解析出的 JavaScript 值(解析值)会经过一次转换后才将被最终返回(返回值)
按照key的顺序从左到右,如果value为对象则先遍历对象里的属性,最里层的属性先开始,一级级往外,最终到达顶层,也就是解析值本身分别的去调用 reviver 函数
如果 reviver 返回 undefined,则当前属性会从所属对象中删除,比如:
JSON.parse(‘{"p": 5}‘, function (k, v) { if(k === ‘‘) return v; // 如果到了最顶层,则直接返回属性值,(最顶层key为空字符串) return v * 2; // 否则将属性值变为原来的 2 倍。 }); // { p: 10 } JSON.parse(‘{"1": 1, "2": 2,"3": {"4": 4, "5": {"6": 6}}}‘, function (k, v) { console.log(k); // 输出当前的属性名,从而得知遍历顺序是从内向外的, // 最后一个属性名会是个空字符串。 return v; // 返回原始属性值,相当于没有传递 reviver 参数。 }); // 1 // 2 // 4 // 6 // 5 // 3 // ""\
2. JSON.stringify(value [, replacer] [, space])
value : 要转换的值
replacer : 可选参数,只能为函数或数组。
如果replacer是函数则表示转换前每个属性会先调用该函数。function(key, value){ return value;} 如果此函数返回 undefined,则排除该成员。和 JSON.parse一样根对象的键是一个空字符串:""。
如果 replacer 是一个数组,则仅转换该数组中具有键值的成员。 成员的转换顺序与键在数组中的顺序一样。 当 value 参数也为数组时,将忽略 replacer 数组。
space : 可选。向返回值 JSON 文本添加缩进、空格和换行符以使其更易于读取。
如果 space 是一个数字,则返回值文本在每个级别缩进指定数目的空格。 如果 space 大于 10,则文本缩进 10 个空格。
如果 space 是一个非空字符串(例如“\t”),则返回值文本在每个级别中缩进字符串中的字符。
如果 space 是长度大于 10 个字符的字符串,则使用前 10 个字符。
如果 value 具有 toJSON 方法,则 JSON.stringify 函数将使用该方法的返回值。 如果 toJSON 方法的返回值为 undefined,则不转换成员,这使对象能够确定自己的 JSON 表示形式。将不会转换不具有 JSON 表示形式的值,例如 undefined。 在对象中,将丢弃这些值。 在数组中,会将这些值替换为 null。
字符串值以引号开始和结束。 所有 Unicode 字符可括在引号中,但必须使用反斜杠进行转义的字符除外。 以下字符的前面必须是反斜杠:
- 引号 (")
- 反斜杠 (\)
- 退格键 (b)
- 换页符 (f)
- 换行符 (n)
- 回车符 (r)
- 水平制表符 (t)
- 四个十六进制数字 (uhhhh)
在序列化过程中,如果 value 参数对应有 toJSON 方法,则 JSON.stringify 将首先调用 toJSON 方法。 如果该方法不存在,则使用原始值。 接下来,如果提供 replacer 参数,则该值(原始值或 toJSON 返回值)将替换为 replacer 参数的返回值。 最后,根据可选 space 参数向该值添加空格以生成最终的 JSON 文本。
eg:第二个参数为数组
var contact = {}; contact.firstname = "Jesper"; contact.surname = "Aaberg"; contact.phone = ["555-0100", "555-0120"]; var memberfilter = []; memberfilter[0] = "surname"; memberfilter[1] = "phone"; var jsonText = JSON.stringify(contact, memberfilter, "\t"); document.write(jsonText); // Output: // { "surname": "Aaberg", "phone": [ "555-0100", "555-0120" ] }
第二个参数为函数:
var continents = []; continents[0] = "Europe"; continents[1] = "Asia"; continents[2] = "Australia"; continents[3] = "Antarctica"; continents[4] = "North America"; continents[5] = "South America"; continents[6] = "Africa"; var jsonText = JSON.stringify(continents, replaceToUpper); function replaceToUpper(key, value) { if (key==‘‘) {return value;} //默认会将整个对象传进来,先过滤掉 return value.toString().toUpperCase(); } //Output: // "EUROPE,ASIA,AUSTRALIA,ANTARCTICA,NORTH AMERICA,SOUTH AMERICA,AFRICA"
对象含有toJSON属性
var contact = {};
contact.firstname = "Jesper";
contact.surname = "Aaberg";
contact.phone = ["555-0100", "555-0120"];
contact.toJSON = function()
{
var replacement = {};
for (var val in this) //当前属性所属的对象会作为 this
值
{
if (typeof (this[val]) === ‘string‘)
replacement[val] = this[val].toUpperCase();
else
replacement[val] = this[val]
}
return replacement;
};
var jsonText = JSON.stringify(contact);
document.write(jsonText);
// Output:
‘{"firstname":"JESPER","surname":"AABERG","phone":["555-0100","555-0120"]}‘
如果对象有toJSON属性方法,而且第二个参数又是函数,则会先调用对象的toJSON属性方法,然后把返回的值再调用第二个函数参数,最后得到的值即为JSON.stringify返回的值:
var a = { ‘a‘: ‘aa‘, ‘aa‘: ‘aaa‘, ‘toJSON‘: function() { var obj = {}; for (var i in this) { //toJSON属性也会加进来 obj[i] = this[i] + ‘xxx‘ } return obj; } }; var b = JSON.stringify(a, function(k, v) { if (k == ‘‘) { return v; } else { return v + ‘ddd‘ } }); console.log(b) //输出: { "a": "aaxxxddd", "aa": "aaaxxxddd", "toJSON": "function (){var obj={};for(var i in this){obj[i]=this[i]+‘xxx‘ } return obj;}xxxddd" }
参考:
https://technet.microsoft.com/zh-cn/sysinternals/cc836459
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse