JSON
格式:JSON(JavaScript Object Notation缩写)是一种用于数据交换的文本格式,目的是取代繁琐笨重的 XML 格式。
(1)规定
-
复合类型的值只能是数组或对象,不能是函数、正则表达式对象、日期对象。
-
原始类型的值只有四种:字符串、数值(必须以十进制表示)、布尔值和
null
(不能使用NaN
,Infinity
,-Infinity
和undefined
)。 -
字符串必须使用双引号表示,不能使用单引号。
-
对象的键名必须放在双引号里面。
-
数组或对象最后一个成员的后面,不能加逗号。
(2)实例:
- 合法JSON
["one", "two", "three"]
{ "one": 1, "two": 2, "three": 3 }
{"names": ["张三", "李四"]
[ { "name": "张三"}, {"name": "李四"} ]
- 不合法JSON
{ name: "张三", 'age': 32 } // 属性名必须使用双引号
[32, 64, 128, 0xFFF] // 不能使用十六进制值
{ "name": "张三", "age": undefined } // 不能使用 undefined
{ "name": "张三",
"birthday": new Date('Fri, 26 Aug 2011 07:13:10 GMT'),
"getName": function () {
return this.name;
}
} // 属性值不能使用函数和日期对象
(3)JSON对象
JSON
对象是 JavaScript 的原生对象,用来处理 JSON 格式数据。它有两个静态方法:JSON.stringify()
和JSON.parse()
。
<1> JSON.stringify()
[1] 基本用法
JSON.stringfy()方法将一个值转为JSON字符串,该字符串符合JSON格式,且可被JSON.parse()还原
例:
JSON.stringify('abc') // ""abc""
JSON.stringify(1) // "1"
JSON.stringify(false) // false
JSON.stringify([]) // "[]"
JSON.stringify({}) // "{}"
JSON.stringify([1,"false",false])
// '[1,"false",false]'
JSON.stringfy({name:"张三"})
// '{name:张三}'
上方将各种类型的值,转为JSON字符串,对于原始类型,转换结果会带双引号
JSON.stringify('foo') === "foo" // false
JSON.stringify('foo') === "\"foo\"" // true
// 上面代码中,如果不是内层的双引号,将来还原的时候,引擎就无法知道原始值是布尔值还是字符串。
JSON.stringify()
方法会忽略对象的不可遍历的属性
var obj = {};
Object.defineProperties(obj,{
'foo':{
value:1,
enumerable:true
},
'bar':{
value:2,
enumerable:false
}
});
JSON.stringify(obj); // "{"foo":1}"
// bar是obj对象的不可遍历属性,JSON.stringify方法将会忽略这个属性
[2] 第二个参数
JSON.stringify()方法还可以接受一个数组,作为第二个参数,指定参数对象的哪些属性需要转为字符串
var obj = {
'prop1':'value1',
'prop2':'value2',
'prop3':'value3'
};
var selectedProperties = ['prop1','prop2'];
JSON.stringify(obj,selectedProperties)
// "{"prop1":"value1","prop2":"value2"}"
// JSON.stringify()方法的第二个参数指定,只转prop1和prop2的两个属性
类似白名单的数组,只对对象的属性有效,对数组无效。
JSON.stringfy(['a','b'],[0]);
// "["a","b"]"
JSON.stringify({0:'a',1:'b'},['0']);
// "{"0":"a"}"
第二个参数还可以是函数,用来更改JSON.stringify()的返回值
function f(key,value) {
if(typeof value === "number") {
value = 2 * value;
}
return value;
}
JSON.stringify({a:1,b:2},f);
// '{"a":2,"b":4}'
// f函数,接受两个参数,分别是被转换的对象的键名和键值。键值为数值的话,将乘2,否则原样返回,
注意:这个处理函数是递归处理所有的键
var obj = {a:{b:1}}
function f(key.value) {
console.log("[" + key + "]:" + value);
return value;
}
JSON.stringify(obj.f);
//[]:[object object]
//[a]:[object object]
//[b]:1
//'{"a":{"b":1}}'
// 对象 obj 一共会被函数 f 处理三次,输出的最后那行是JSON.stringify()的默认输出,第一次键名为空,键值是整个对象的obj;第二次键名为a,键值是{b:1};第三次键名为b,键值为1
递归处理中,每一次处理的对象,都是前一次返回的值
var obj = {a:1};
function f(key,value) {
if (typeof value === 'object') {
return {b:2};
}
return value * 2;
}
JSON.stringify(obj,f);
// "{"b":4}"
// 上面代码中,f函数修改了对象obj,接着JSON.stringify()方法就递归处理修改后的对象obj
如果处理函数返回undefined或没有返回值,则该属性会被忽略
function f(key,value) {
if (typeof(value) === "string") {
return undefined;
}
return value;
}
JSON.stringify({a:"abc",b:123},f)
// '{"b":123}'
// a属性被处理后,返回undefined,于是该属性被忽略
[3] 第三个参数
JSON.stringify()还可以接受第三个参数,用于增加返回的JSON字符串的可读性
默认返回单行字符串,对于大型JSON对象,可读性差。第三个参数使得每个属性单独占据一行,并将每个属性前面添加指定的前缀(前缀不超过10个字符)
// 默认输出
JSON.stringify({p1:1,p2:2})
// JSON.stringify({p1:1,p2:2})
// 分行输出
JSON.stringify({p1:1,p2:2},null,'\t')
/*
{
"p1":1,
"p2":2
)
*/
// 第三个属性\t在每个属性前面添加一个制表符(从当前位置移动到下一个tab位置),然后分行显示
第三个属性如果是数字,则表示在每个属性前面添加的空格(不超过10个)
JSON.stringify({ p1: 1, p2: 2 }, null, 2);
/*
"{
"p1": 1,
"p2": 2
}"
*/
<2> JSON.parse()
JSON.parse()
方法用于将 JSON 字符串转换成对应的值。
例1:
JSON.parse('{}'); // {}
JSON.parse('true'); // true
JSON.parse('"foo"'); // "foo"
JSON.parse('[1,5,"false"]'); // [1,5,"false"]
JSON.parse('null'); // null
var o = JSON.parse('{"name":"张三"}');
o.name // 张三
例2:传入字符串不是有效的JSON格式,将报错
JSON.parse("'String'");
// 报错
// 双引号字符串中是一个单引号字符串,因为单引号字符串不符合JSON格式,所以报错
try...catch代码块,解析错误
try {
JSON.parse("'String'");
}catch(e) {
console.log('parsing error');
}
JSON.parse()方法接受一个处理函数,作为第二个参数,用法与JSON.stringify()方法类似
function f(key,value) {
if (key === 'a') {
return value + 10;
}
return value;
}
JSON.parse('{"a":1,"b":2}',f);
// {a:11,b:2}
// JSON.parse()的第二个参数是一个函数,如果键名是a,该函数会将键值加上10
函数声明
js中有三种声明函数的方法
(1)function命令
function命令声明的代码区块,就是一个函数。function命令后面是函数名,函数名后面是一对圆括号,里面是传入函数的参数。函数体放在大括号里面
function print(s) {
console.log(s);
}
// 代码中命名了一个print函数,使用print()这种形式,就可以调用相应的代码,这叫做函数的声明
(2)函数表达式
funciton命令声明函数,还可采用变量赋值的写法
var print = function(s) {
console.log(s);
}
// 将一个匿名函数赋值给变量,匿名函数又被称为函数表达式,赋值语句右侧只能放表达式
采用函数表达式声明函数时,function命令后面不带有函数名。加上函数名,则函数名只在函数体内部有效,在函数体外部无效
var print = funciton x() {
coonsole.log(typeof x);
};
print();
// funciton
// 上面代码在函数表达式中,加入了函数x。x只在函数体内部可用,指代函数表达式本身,其他地方都不可用
// 两种用法:
//(1)函数体内部调用自身
//(2)方便除错(除错工具显示函数调用栈时,显示函数名,而不再显示这里是一个匿名函数)
var f = funciton f() {};
函数表达式末尾加分号,表示语句结束;而函数声明在结尾的大括号后面不用加分号。
(3)Function构造函数
var add = new Function(
'x',
'y',
'return x + y'
);
// 等同于
function add(x,y) {
return x + y;
}
// Function构造函数接受三个参数,除了最后一个参数是add函数的“函数体”,其他参数都是add函数的参数
可传递任意数量参数给Function构造函数,仅最后一个参数会被当做函数体;若仅一个参数,该参数就是函数体
var foo = new Function(
'return "hello world";'
);
// 等同于
function foo() {
return "hello world";
}
// function构造函数可不使用new命令,返回结果相同。(声明函数的方式不直观,无人使用)