JSON是一种轻量级的文本数据交换格式,并不是一种编程语言,多种编程语言都提供了对JSON的序列化和解析的方法;ES5定义了一个原生的全局对象JSON并对其进行了规范,支持的浏览器包括IE8+等

JSON的优势:
1、轻量级,格式简单、易于读写;
2、数据是压缩的,占用带宽小;
3、易于解析;
4、支持多种语言,包括C、C#、JAVA、Python、PHP等;


JSON语法

JSON不支持变量、函数和对象的实例,不支持JavaScript中的undefined;

JSON支持的三种类型的值:

1、简单值:包括布尔值、数值、字符串和null;

2、数组:表示一种有序值的列表的复杂数据类型,数组的值可以是JSON支持的任意数据类型,包括简单值、数组或对象;JSON数组采用字面量的形式表示;

3、对象:表示一种有序键值对的复杂数据类型,对象的值同样可以是任意支持的数据类型; JSON中对象的表示和JavaScript中的表示有一些区别;JavaScript对于对象的字面量的标准形式是属性名不加引号,但是JSON中的属性名和值一样也需要加双引号;不加双引号或者加入了单引号都会导致错误;另外,JSON对象中的同一对象不应该出现两个同名属性;

其实,在JavaScript中给属性名加入引号,仍然可以像标准形式那样正常访问,这是允许的;

json javascript 最前面加一个元素_stringify


JSON序列化与反序列化

JSON对象的stringify()和parse()方法用于序列化和解析JSON对象;

stringify(jsObj, filter, flag):

用于将JS对象序列化为JSON字符串,其默认结果不包含任何空格或者缩进;

序列化的过程中会忽略undefined、函数、symbol及原型对象;但是如果undefined、函数或symbol类型在数组中将会返回null

不论是否使用了filter函数,所有symbol做属性名的键值对均会被忽略;

不可枚举的属性将会被忽略;

仅在传入纯值(function () {}, undefined, Symbol(”)等时)JSON.stringify()才会返回undefined;

json javascript 最前面加一个元素_JSON特点_02

如下图可以看到默认模式下JSON.stringify()会忽略所有的空格和缩进;同时,JSON.parse()得到的JS对象和原始的JS对象并不是一个对象,因此可以考虑用于深拷贝;同时,JSON字符串属性值都使用了双引号;

json javascript 最前面加一个元素_JSON应用_03

JSON.stringify()函数接受三个参数:第一个参数表示序列化的JS对象(必须);第二个参数是一个filter(可选),可以为一个数组或函数;第三个参数用于控制是否保留缩进,可以为数值或者字符串(不管是数字还是字符串,大于10会转换为10),为数值时表示缩进的空格数,同时可能会保留JS对象中的换行符;

json javascript 最前面加一个元素_JSON应用_04

当使用函数过滤器时,接受属性名和属性值两个参数,根据属性名对属性值进行相应的处理;函数有返回值,会作为相应属性的值;返回值为undefined时最终结果会自动删除相应的键值对;在值为非键值对结构时,属性名可以为空字符串;

json javascript 最前面加一个元素_stringify_05

toJSON()方法

toJSON()可以看作是JSON.stringify()的函数过滤器的一个补充,以满足某些自定义序列化的需求;toJSON()通常需要定义在对象上,返回值为对应的序列化字符串;

json javascript 最前面加一个元素_parse_06

如果toJSON()方法return的是undefined,如果为最顶层的对象,那么最终会返回结果是undefined(与调用JSON.stringify(undefined)类似);如果不是,那么最终结果会忽略对应的对象;

json javascript 最前面加一个元素_JSON应用_07

JSON.stringify()序列化顺序如下:
1、若存在toJSON()能取得它的有效值,那么直接调用该方法;否则按照默认顺序执行;
2、如果提供了filter参数,把第一步返回的值作为参数,调用filter;
3、序列化第二步返回的每个值;
4、若存在第三个参数,进行相应的格式化调整;

  • 这里toJSON()方法直接定义在顶级对象中,可以直接取得有效值,仅进行了步骤一并直接返回值;
  • json javascript 最前面加一个元素_JSON应用_08

  • 这里toJSON()方法定义在内部对象中,不能直接取得有效值,,并且提供了filter函数;这里会先调用toJSON()得到结果,然后再使用filter函数像处理普通的JSON.stringify()一样为每一项调用filte()函数;
  • json javascript 最前面加一个元素_parse_09


JSON.parse()

与JSON.stringify()类似,JSON.parse()同样提供了第二个参数,不过该参数是还原函数而非过滤函数;该函数同样接受键、值两个参数;若返回值为undefined,则从结果中删除相应的键值对;常用的场景是将日期字符串转为Date对象以便使用Date相关的内置函数(Date对象经过stringify()及parse()还原后得到的是一个字符串类型);

var info = {
  name: 'fn',
  age: 25,
  grades: {
      subjectA: 90,
      subjectB: 98,
      subjectC: 99,
      toJSON: function () {
        return this.subjectB;
      }
  },
  interests: ['basketball', 'music', 'movies'],
  dateInfo: new Date()
};

var jsonString = JSON.stringify(info);
console.log(jsonString);

var infoCopy = JSON.parse(jsonString, function (key, value) {
  if (key === 'dateInfo') {
    return new Date(value);
  } else {
    return value;
  }
});

console.log(infoCopy);
console.log(infoCopy.dateInfo.getFullYear());

json javascript 最前面加一个元素_JSON应用_10


应用

本地存储

利用JSON.stringify()和JSON.parse()可以用于localStorage进行本地存取数据;

var info = {
  time: new Date(),
  newUser: true,
  user: {
    name: 'fn',
    age: 20,
    address: 'Shanghai'
  }
};

var restoredInfo = localStorage.setItem('info', JSON.stringify(info));
console.log(restoredInfo);

var result = JSON.parse(localStorage.getItem('info'), function(key, val) {
  if (key === 'time') {
    return new Date(val);
  } else {
    return val;
  }
});

console.log(result.time.getFullYear()); // 2017

深拷贝

使用JSON.stringify()和JSON.parse()可以实现简单的深拷贝;

json javascript 最前面加一个元素_JSON_11

jsonP

jsonp中当请求一个外域的资源时,通常会将回调函数名作为参数加在请求体中,而后端过滤到回调函数名后,通常会将请求调用回调函数的表达式以JSON格式返回,客户端需要使用eval()等进行解析并执行回调;