阿西河

所有教程

公众号
🌙
阿西河前端的公众号

我的收藏

    最近访问  (文章)

      教程列表

      抓包专区
      测试专区

      JavaScript JSON解析与序列化

      解析与序列化

      JSON 之所以流行,拥有与 JavaScript 类似的语法并不是全部原因,更重要的一个原因是,可以很容易把JSON 数据结构解析为有用的 JavaScript 对象

      bookThreeTitle=books[2].title

      下面是在 DOM结构中查找数据的代码:

      bookThreeTitle=loadXMLDoc(“books.xml”).getElementsByTagName(“book”)[2].getAttribute(“title”)

      看看这些多余的方法调用,就不难理解为什么 JSON 能得到 JavaScript 开发人员的热烈欢迎了。从s此以后,JSON 就成了 Web 服务开发中交换数据的事实标准。

      • JSON对象
      • 序列化选项
      • 解析选项

      JSON对象

      JSON 对象有两个方法: stringify() 和 parse() 。在最简单的情况下,这两个方法分别用于把JavaScript 对象序列化为 JSON 字符串和把 JSON 字符串解析为原生 JavaScript 值。

      也可以使用JavaScript 的 eval() 函数来解析JSON字符串,但是使用 eval() 对 JSON 数据结构求值存在风险,因为可能会执行一些恶意代码。还有就是比较好性能;(eval可以解析任何字符串,属于比较底层的方法,虽然通杀但是一般不会使用;)

      JSON.stringify的用法,JSON对象转为JSON字符串

      var JSONObj = {
          title: "Professional JavaScript",
          authors: [
              "Nicholas C. Zakas"
          ],
          edition: 3,
          year: 2011,
          testUndefined:undefined,
          testFunction:function(){return 2+2}
      };
      var JSONStr = JSON.stringify(JSONObj);
      console.log(JSONStr);//{"title":"Professional JavaScript","authors":["Nicholas C. Zakas"],"edition":3,"year":2011}
      console.log(typeof JSONObj);//object
      console.log(typeof JSONStr);//string
      

      默认情况下, JSON.stringify() 输出的 JSON 字符串不包含任何空格字符或缩进,

      在序列化 JavaScript 对象时,所有函数及原型成员都会被有意忽略,不体现在结果中。此外,值为undefined 的任何属性也都会被跳过。结果中最终都是值为有效 JSON 数据类型的实例属性。

      上面的 testUndefined* 和 **testFunction** 将不会出现最终的结果中;

      JSON.parse的用法,JSON字符串转为JSON对象;

      var JSONStr1 = '{title: "Professional JavaScript",authors: ["Nicholas C. Zakas"],edition: 3,year: 2011}';
      var JSONStr2 = '{"title": "Professional JavaScript","authors": ["Nicholas C. Zakas"],"edition": 3,year: 2011}';
      var JSONStr3 = '{"title": "Professional JavaScript","authors": ["Nicholas C. Zakas"],"edition": 3,"year": 2011}';
      var JSONStr4 = '{"title": "Professional JavaScript","authors": ["Nicholas C. Zakas"],"edition": 3,"year": 2011,"testUndefined":undefined}';
      
      //var JSONObj1 = JSON.parse(JSONStr1);      // 报错啦,属性值没有""
      //var JSONObj2 = JSON.parse(JSONStr2);      // 报错啦,属性值没有全部用""
      var JSONObj3 = JSON.parse(JSONStr3);        // 成功
      //var JSONObj4 = JSON.parse(JSONStr4);        // 报错啦,不能含有undefined,function等数据
      console.log(JSONObj3);//{"title":"Professional JavaScript","authors":["Nicholas C. Zakas"],"edition":3,"year":2011}
      console.log(typeof JSONObj3);//object
      

      如果传给 JSON.parse() 的字符串不是有效的 JSON,该方法会抛出错误。

      序列化选项 ( JSON.stringify()的深入理解 )

      实际上, JSON.stringify() 除了要序列化的 JavaScript 对象外,还可以接收另外两个参数,这两个参数用于指定以不同的方式序列化 JavaScript 对象。第一个参数是个过滤器,可以是一个数组,也可以是一个函数;第二个参数是一个选项,表示是否在 JSON 字符串中保留缩进。单独或组合使用这两个参数,可以更全面深入地控制 JSON 的序列化

      JSON.stringify(jsonObj,arguments1,arguments2)

      • arguments1 过滤器的作用,用来过滤结果;
      • arguments2 字符串缩进的作用;

      过滤器(用来过滤结果)

      • 数组过滤

        var book={ “title”:“book title”, authors:[ “one”, “two”, “three” ], edition:2, year:2016 }; var JSONStr=JSON.stringify(book,[“title”,“year”,“other”]); console.log(JSONStr);//{“title”:“book title”,“year”:2016} console.log(typeof JSONStr);//string

      JSON.stringify() 的第二个参数是一个数组,其中包含三个字符串: “title”、“year”、“other”。这两个属性与将要序列化的对象中的属性是对应的,因此在返回的结果字符串中,就只会包含这两个属性;因为源数据中没有other这个键值对;匹配不到,就会忽略掉;

      • 函数过滤

        var book={ “title”:“book title”, authors:[ “one”, “two”, “three” ], edition:2, year:2016 }; var JSONStr=JSON.stringify(book,function(key,value){ switch (key){ case “authors”: return value.join("+++++");//如果键为 “authors” ,就将数组连接为一个字符串; case “year”: return 5000+“change”;//如果键为 “year” ,则将其值设置为 5000change ; case “edition”: return undefined;//如果键为 “edition” ,通过返回 undefined 删除该属性 default : return value;//最后,一定要提供 default 项,此时返回传入的值,以便其他值都能正常出现在结果中。 } }); console.log(JSONStr);//{“title”:“book title”,“authors”:“one+++++two+++++three”,“year”:“5000change”} console.log(typeof JSONStr);//string

      这里,函数过滤器根据传入的键来决定结果

      Firefox 3.5 和 3.6 对 JSON.stringify() 的实现有一个 bug,在将函数作为该方法的第二个参数时这个 bug 就会出现,即这个函数只能作为过滤器:返回 undefined 意味着要跳过某个属性,而返回其他任何值都会在结果中包含相应的属性。Firefox 4 修复了这个 bug。(未亲自验证)

      字符串缩进

      var book={
          "title":"book title",
          authors:[
              "one",
              "two",
              "three"
          ],
          edition:2,
          year:2016
      };
      var JSONStr=JSON.stringify(book,null,4);
      console.log(JSONStr);
      console.log(typeof JSONStr);//string
      

      输出的结果如下:

      {
          "title": "book title",
          "authors": [
              "one",
              "two",
              "three"
          ],
          "edition": 2,
          "year": 2016
      }
      

      也可以用字符替换空格

      var JSONStr=JSON.stringify(book,null,"- - ");
      

      最终结果如下:

      {
      - - "title": "book title",
      - - "authors": [
      - - - - "one",
      - - - - "two",
      - - - - "three"
      - - ],
      - - "edition": 2,
      - - "year": 2016
      }
      

      JSON.stringify() 也在结果字符串中插入了换行符以提高可读性。只要传入有效的控制缩进的参数值,结果字符串就会包含换行符。最大缩进空格数为 10,所有大于 10 的值都会自动转换为 10

      缩进字符串最长不能超过 10 个字符长。如果字符串长度超过了 10 个,结果中将只出现前 10 个字符。

      toJSON() 方法

      var book={
          "title":"book title",
          authors:[
              "one",
              "two",
              "three"
          ],
          edition:2,
          year:2016,
          toJSON:function (){
              return this.title;
          }
      };
      var JSONStr=JSON.stringify(book);
      console.log(JSONStr);//"book title"
      console.log(typeof JSONStr);//string
      

      可以给对象定义 toJSON() 方法,返回其自身的 JSON 数据格式。 toJSON() 可以作为函数过滤器的补充,因此理解序列化的内部顺序十分重要。

      假设把一个对象传入 JSON.stringify() ,序列化该对象的顺序如下。

      • (1) 如果存在 toJSON() 方法而且能通过它取得有效的值,则调用该方法。否则,返回对象本身。
      • (2) 如果提供了第二个参数,应用这个函数过滤器。传入函数过滤器的值是第(1)步返回的值。
      • (3) 对第(2)步返回的每个值进行相应的序列化。
      • (4) 如果提供了第三个参数,执行相应的格式化。

      无论是考虑定义 toJSON() 方法,还是考虑使用函数过滤器,亦或需要同时使用两者,理解这个顺序都是至关重要的。

      解析选项 ( JSON.parse()的深入理解 )

      var JSONStr = '{"title": "标题","authors": ["one","two","rhree"],"edition": 3,"year": 2016,"releaseDate": "2016,10,08 12:59:01"}';
      var JSONObj1 = JSON.parse(JSONStr);
      console.log(JSONObj1);
      console.log(typeof JSONObj1);//object
      
      var JSONObj2 = JSON.parse(JSONStr,function(key,value){
          if(key === "releaseDate"){
              return new Date(value);
          }else{
              return value;
          }
      });
      console.log(JSONObj2);
      console.log(typeof JSONObj2);//object
      
      console.log(JSONObj2.releaseDate.getFullYear()+" - "+JSONObj2.releaseDate.getMinutes());//2016 - 59
      

      结果就是 JSONObj2.releaseDate 属性中会保存一个 Date 对象。正因为如此,才能基于这个对象调用getFullYear() 等方法。

      目录
      目录