zoukankan      html  css  js  c++  java
  • 深入理解JSON对象

      json(javascript object notation)全称是javascript对象表示法,它是一种数据交换的文本格式,而不是一种编程语言,用于读取结构化数据。2001年由Douglas Crockford提出,目的是取代繁琐笨重的XML格式。本文将详细介绍JSON的相关内容

    JSON的语法可以表示以下三种类型的值 

    语法规则

      JSON的语法可以表示以下三种类型的值

    【1】简单值

      简单值使用与javascript相同的语法,可以在JSON中表示字符串、数值、布尔值和null

      字符串必须使用双引号表示,不能使用单引号。数值必须以十进制表示,且不能使用NaN和Infinity

      [注意]JSON不支持javascript中的特殊值undefined

    //合格的简单值
    5
    "hello world"
    true
    null
    //不合格的简单值
    +0x1
    'hello world'
    undefined
    NaN
    Infinity

    【2】对象

      对象作为一种复杂数据类型,表示的是一组有序的键值对儿。而每个键值对儿中的值可以是简单值,也可以是复杂数据类型的值

      与javascript的对象字面量相比,JSON有三个不同的地方

      1、JSON没有变量的概念

      2、JSON中,对象的键名必须放在双引号里面

      3、因为JSON不是javascript语句,所以没有末尾的分号

      [注意]同一个对象中不应该出现两个同名属性

    //合格的对象
    {
        "name":"huochai",
        "age":29,
        "school":{
            "name":"diankeyuan",
            "location":"beijing"
        }
    }
    //不合格的对象
    { name: "张三", 'age': 32 }//属性名必须使用双引号
    {};//不需要末尾的分号
    { "birthday": new Date('Fri, 26 Aug 2011 07:13:10 GMT'),
      "getName": function() {
          return this.name;
      }
    } // 不能使用函数和日期对象

    【3】数组

      数组也是一种复杂数据类型,表示一组有序的值的列表,可以通过数值索引来访问其中的值。数组的值也可以是任意类型——简单值、对象或数组

      JSON数组也没有变量和分号,把数组和对象结合起来,可以构成更复杂的数据集合

      [注意]数组或对象最后一个成员的后面,不能加逗号

    JSON对象

      JSON之所以流行,是因为可以把JSON数据结构解析为有用的javascript对象

      ECMAScript5对解析JSON的行为进行了规范,定义了全局对象JSON

      [注意]IE7-浏览器不支持

      IE7-浏览器可以通过使用json2.js文件来使用JSON

      JSON对象有两个方法:stringify()和parse()。这两个方法分别用于把JavaScript对象序列化为JSON字符串和把JSON字符串解析为原生JavaScript值

    stringify()

      JSON.stringify()方法用于将一个值转为字符串。该字符串应该符合JSON格式,并且可以被JSON.parse()方法还原 

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

    var jsonObj = {
        "title":"javascript",
        "group":{
            "name":"jia",
            "tel":12345
        }
    };
    //{"title":"javascript","group":{"name":"jia","tel":12345}}
    JSON.stringify(jsonObj);

    具体转换

    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.stringify({ name: "张三" })// '{"name":"张三"}'

    stringify()方法把正则表达式和数学对象转换成空对象的字符串形式

    JSON.stringify(/foo/) // "{}"
    JSON.stringify(Math) // "{}"

    stringify()方法把日期对象和包装对象转换成字符串

    JSON.stringify(new Boolean(true)) //"true"
    JSON.stringify(new String('123')) //""123""
    JSON.stringify(new Number(1)) //"1"
    JSON.stringify(new Date()) //""2016-09-20T02:26:38.294Z""

      如果对象的成员是undefined或函数,这个成员会被省略

      如果数组的成员是undefined或函数,则这些值被转成null

    JSON.stringify({
      a: function(){},
      b: undefined,
      c: [ function(){}, undefined ]
    });
    // "{"c":[null,null]}"

    如果对象成员或数组成员中出现NaN或Infinity,则这些值被转换成null

    console.log(JSON.stringify({
      a: NaN,
      b: Infinity,
      c: [ NaN,Infinity]
    }));
    //{"a":null,"b":null,"c":[null,null]}

    JSON.stringify()方法会忽略对象的不可遍历属性

    var obj = {};
    Object.defineProperties(obj, {
      'foo': {
        value: 1,
        enumerable: true
      },
      'bar': {
        value: 2,
        enumerable: false
      }
    });
    JSON.stringify(obj); // {"foo":1}]

    参数

      JSON.stringify()除了要序列化的javascript对象外,还可以接收另外两个参数,这两个参数用于指定以不同的方式序列化javascript对象。第一个参数是个过滤器,可以是一个数组,也可以是一个函数;第二个参数是一个选项,表示是否在JSON字符串中保留缩进

    【数组过滤器】

      当stringify()方法的第二个参数是一个数组时,这时相当于实现一个过滤器的功能

      【1】过滤器只对对象的第一层属性有效

    var jsonObj = {
        "title":"javascript",
        "group":{
            "a":1
        }
    };
    //{"group":{"a":1}}
    console.log(JSON.stringify(jsonObj,["group","a"]))

      【2】过滤器对数组无效

    var jsonObj =[1,2];
    JSON.stringify(jsonObj,["0"])//"[1,2]"

    【函数参数】

      stringify()方法的第二个参数也可以是一个函数。传入的函数接收两个参数,属性(键)名和属性值

    JSON.stringify({a:1,b:2}, function(key, value){
      if (typeof value === "number") {
        value = 2 * value;
      }
      return value;    
    })
    // "{"a":2,"b":4}"

      属性名只能是字符串,而在值并非键值对儿结构的值时,键名可以是空字符串

      这个函数参数会递归处理所有的键

      下面代码中,对象o一共会被f函数处理三次。第一次键名为空,键值是整个对象o;第二次键名为a,键值是{b:1};第三次键名为b,键值为1

    JSON.stringify({a: {b: 1}}, function (key, value) {
      console.log("["+ key +"]:" + value);
      return value;
    })
    // []:[object Object]
    // [a]:[object Object]
    // [b]:1
    // '{"a":{"b":1}}'    

    函数返回的值就是相应键的值。如果函数返回了undefined或没有返回值,那么相应的属性会被忽略

    JSON.stringify({ a: "abc", b: 123 }, function (key, value) {
      if (typeof(value) === "string") {
        return undefined;
      }
      return value;
    })
    // '{"b": 123}'

    【缩进】

      stringify()方法还可以接受第三个参数,用于增加返回的JSON字符串的可读性

      如果是数字,表示每个属性前面添加的空格(最多不超过10个)

      如果是字符串(不超过10个字符),则该字符串会添加在每行前面

    /*"{
      "p1": 1,
      "p2": 2
    }"*/
    JSON.stringify({ p1: 1, p2: 2 }, null, 2);
    //"{"p1":1,"p2":2}"
    JSON.stringify({ p1: 1, p2: 2 }, null, 0);
    /*"{
    |-"p1": 1,
    |-"p2": 2
    }"*/
    JSON.stringify({ p1:1, p2:2 }, null, '|-');

    toJSON()

      有时候,JSON.stringify()还是不能满足对某些对象进行自定义序列化的需求。在这些情况下, 可以通过在对象上调用toJSON()方法,返回其自身的JSON数据格式

    JSON.stringify({
      toJSON: function () {
        return "Cool"
      }
    })
    // ""Cool""
    var o = {
      foo: 'foo',
      toJSON: function() {
        return 'bar';
      }
    };
    JSON.stringify({x: o});// '{"x":"bar"}'

    如果toJSON()方法返回undefined,此时如果包含它的对象嵌入在另一个对象中,会导致该对象的值变成null。而如果包含它的对象是顶级对象,结果就是undefined

    JSON.stringify({
      toJSON: function () {
        return undefined
      }
    })
    //undefined

    Date对象部署了一个自己的toJSON方法,自动将Date对象转换成日期字符串

    JSON.stringify(new Date("2016-08-29"))
    // "2016-08-29T00:00:00.000Z"

    toJSON方法的一个应用是,可以将正则对象自动转为字符串

    RegExp.prototype.toJSON =RegExp.prototype.toString;
    JSON.stringify(/foo/)// ""/foo/""

    toJSON()可以作为函数过滤器的补充,因此理解序列化的内部顺序十分重要。假设把一个对象传入JSON.stringify(),序列化该对象的顺序如下

      1、如果存在toJSON()方法而且能通过它取得有效的值,则调用该方法。否则,按默认顺序执行序列化

      2、如果提供了第二个参数,应用这个函数过滤器。传入函数过滤器的值是第一步返回的值

      3、对第二步返回的每个值进行相应的序列化

      4、如果提供了第三个参数,执行相应的格式化

    parse()

      JSON.parse方法用于将JSON字符串转化成对象

    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 // 张三

    如果传入的字符串不是有效的JSON格式,JSON.parse方法将报错

    //Uncaught SyntaxError: Unexpected token u in JSON at position 0(…)
    JSON.parse("'String'") 
    
    //Uncaught SyntaxError: Unexpected token u in JSON at position 0(…)
    JSON.parse("undefined")

    JSON.parse()方法也可以接收一个函数参数,在每个键值对儿上调用,这个函数被称为还原函数(reviver)。该函数接收两个参数,一个键和一个值,返回一个值

      如果还原函数返回undefined,则表示要从结果中删除相应的键;如果返回其他值,则将该值插入到结果中

    var o = JSON.parse('{"a":1,"b":2}', function(key, value) {
      if (key === ''){
        return value;
      }
      if (key === 'a') {
        return value + 10;
      }
    });
    o.a // 11
    o.b // undefined

    在将日期字符串转换为Date对象时,经常要用到还原函数

    var book = {
        "title": "javascript",
        "date": new Date(2016,9,1)
    }
    var jsonStr = JSON.stringify(book);
    //'{"title":"javascript","date":"2016-09-30T16:00:00.000Z"}''
    console.log(jsonStr)
    
    var bookCopy = JSON.parse(jsonStr,function(key,value){
        if(key == 'date'){
            return new Date(value);
        }
        return value;
    })
    console.log(bookCopy.date.getFullYear());//2016

    eval()

      实际上,eval()类似于JSON.parse()方法,可以将json字符串转换为json对象

    eval('(' + '{"a":1}'+')').a;//1
    JSON.parse('{"a":1}').a;//1

    但是,eval()可以执行不符合JSON格式的代码,有可能会包含恶意代码

    val('(' + '{"a":alert(1)}'+')').a;//弹出1
    JSON.parse('{"a":alert(1)}').a;//报错

    所以,还是要尽量少使用eval()

    校验

      正确的JSON格式需要符合一定的语法规则,使用jsonlint.com网站可以对JSON进行格式校验

  • 相关阅读:
    70.BOM
    69.捕获错误try catch
    68.键盘事件
    523. Continuous Subarray Sum
    901. Online Stock Span
    547. Friend Circles
    162. Find Peak Element
    1008. Construct Binary Search Tree from Preorder Traversal
    889. Construct Binary Tree from Preorder and Postorder Traversal
    106. Construct Binary Tree from Inorder and Postorder Traversal
  • 原文地址:https://www.cnblogs.com/ycg-myblog/p/9836466.html
Copyright © 2011-2022 走看看