• JSON


    JavaScript对象表示法(JavaScript Object Notation,简称JSON)是一种轻量级的数据交换格
    式。它基于JavaScript的对象字面量表示法,那是JavaScript最精华的部分之一。尽管只是
    JavaScript的一个子集,但它与语言武官。它可以被用于在所有以现代编程语言编写的程序
    之间交换数据。它是一种文本格式,所以可以被人和机器阅读。它易于实现且易于使用。


    1、JSON语法

    JSON有6种类型的值:对象、数组、字符串、数字、布尔值(true和false)和特殊值
    null。空白(空格符、制表符、回车符和换行符)可被插到任何值的前后。这可以使的JSON
    文本更容易被人阅读。为了减少传输和存储的成本,空白可以被省略。

    JSON对象是一个容纳“名/值”对的无序集合。名字可以是任何字符串。值可以是任何类
    型的JSON值,包括数组和对象。JSON对象可以被无限层地嵌套,但一般来说保持其结构
    的相对扁平是最高效的。大多数语言都有容易被映射为JSON对象的数据类型,比如对象
    (object)、结构(struct)、字典(dictionary)、哈西表(hash table)、属性列表(prototype list)
    或关联数组(associative array)。

    JSON数组是一个值的有序序列。其值可以是任何类型的JSON值,包括数组和对象。大多
    数语言都有容易被映射为JSON数组的数据类型,比如数组(array)、向量(vector)、列表
    (list)或序列(sequence)。

    JSON字符串要被包围在一对双引号之间。\字符被用于转义。JSON允许/字符被转义,所
    以JSON可以被嵌入HTML的<script>标签中。除非用</script>标签初始化,否则HTML
    不允许使用</字符序列。但JSON允许使用<\/,它能产生同样的结果却不会与HTML
    相混淆。

    JSON数字与JavaScript的数字相似。整数的首位不允许为0,因为一些语言用它来标示八
    进制。这种基数的混乱在数据交换格式中是不可取的。数字可以是整数、实数或科学计数。

    就是这样。这就是JSON的全部。JSON的设计目标是成为一个极简的轻便的和文本式的
    JavaScript子集。实现互通所需要的共识越少,互通就越容易实现。

    [
       {
        "first":"Jerome",
        "middle":"Lester",
        "last":"Howard",
        "nick-name":"Curly",
        "born":1903,
        "died":1952,
        "quote":"nyuk-nyuk-nyuk!"
       },
       {
        "first":"Harry",
        "middle":"Moses",
        "last":"Howard",
        "nick-name":"Moe",
        "born":1897,
        "died":1975,
        "quote":"Why,you!"
       },
       {
        "first":"Louis",
        "last":"Feinberg",
        "nick-name":"Larry",
        "born":1902,
        "died":1975,
        "quote":"I'm sorry.Moe,it was an accident!"
       }
    ]


    2、安全地使用JSON

    JSON特别易于用在Web应用中,因为JSON就是JavaScript。使用eval函数可以把一段
    JSON文本转化成一个有用的数据结构:

    var myData=eval('('+myJSONText+')');

    (用圆括号把JSON文本括起来是一种避免JavaScript语法中的歧义(译注1)的变通方案。)

    ———————————————————————————————
    译注1: 在JavaScript的语法中,表达式语句(Expression Statement)不允许以花括号“{”开
         始,因为那会与块语句(Block Statements)产生混淆。在使用eval()解析JSON文本时,为了
         解决此问题,可以将JSON文本套上一对圆括号。圆括号在此处作为表达式的分组运算
         符,能对包围在其中的表达式进行求值。它能正确地识别对象字面量。

    然而,eval函数有着骇人的安全问题。用eval去解析JSON文本安全吗?目前,在Web
    浏览器中从服务器端获取数据的最佳技术是XMLHttpRequest。XMLHttpRequest只能从生成
    HTML的同意服务器获取数据。使用eval解析来自那个服务器的文本安全性和解析最初
    HTML的安全性一样低。那是假定该服务器存有恶意的前提下,但如果它只是存在漏洞呢?

    有漏洞的服务器或许并不能正确地对JSON进行编码。如果它通过拼凑一些字符串而不是使
    用一个合适的JSON编码器来创建JSON文本,那么它可能在无意间发送危险的数据。如果
    它充当的是代理的角色,并且尚未确定JSON文本是否格式良好就简单地传递它,那么它可
    能再次发送了危险数据。

    通过使用JSON.parse(译注2)方法替代eval就能避
    免这种危险。如果文本中包含任何危险数据,那么JSON.parse将抛出一个异常。为了防止
    服务器出现漏洞的状况,我推荐你总是用JSON.parse替代eval。即使有一天浏览器提
    供了连到其他服务器的安全数据访问,使用它同样是个好习惯。

    ——————————————————————————————
    译注2:原生JSON支持的需求已被提交为ES3.1的工作草案,另外IE8已经提供了原生的JSON支持。

    在外部数据与innerHTML进行交互时还存在另一种危险。一种常见的Ajax模式是把服务器端
    发送过来的一个HTML文本片段赋值给某个HTML元素的innerHTML属性。这是一个非
    常糟糕的习惯。如果这个HTML包含一个<script>标签或其等价物,那么一个恶意脚本将
    被运行。这可能又是因为服务端存在漏洞。

    具体有什么危险呢?如果一个恶意脚本在你的页面上被运行,它就有权访问这个页面的所
    有的状态和该页面能做的操作。它能与你的服务器进行交互,而你的服务器将不能区分正
    当请求和恶意请求。恶意脚本还能访问全局对象,这使得它有权访问该应用中除隐藏于闭
    包中的变量之外的所有数据。它可以访问document对象,这会使它有权访问用户所能看到
    的一切。它还给这个恶意脚本提供了与用户进行会话的能力。浏览器的地址栏和所有的反
    钓鱼程序将告诉用户这个会话是可靠的。document对象还给该恶意脚本授权访问网络,允
    许它去下载更多的恶意脚本,或者是在你的防火墙之内探测站点,或者是将它已经窃取的
    隐私内容发送给世界的任何一个服务器。

    这个危险是JavaScript全局变量的直接后果,它是JavaScript众多糟粕之中最糟糕的一个。
    这些危险并不是由Ajax、JSON、XMLHttpRequest或Web 2.0(不管它是什么)导致的。
    自从JavaScript被引入浏览器,这些危险就已经存在了,并且它将一直存在,直到JavaScript
    有一天被取代。所以,请务必当心。


    3、一个JSON解析器

    这是一个用JavaScript编写的JSON解析器的实现方案:

    var json_parse=function(){
       //这是一个能把JSON文本解析成JavaScript数据结构的函数。
       //它是一个简单的递归降序解析器。
       //我们在另一个函数中定义此函数,以避免创建全局变量
       var at,   //当前字符的索引
        ch,   //当前字符
        escapee={
         '"':'"',
         '\\':'\\',
         '/':'/',
         b:'b',
         f:'\f',
         n:'\n',
         r:'\r',
         t:'\t'
        },
        text,
        error=function(m){
         //当某处出错时,调用error。
         throw{
          name:'SyntaxError',
          message:m,
          at:at,
          text:text
         };
        },
        next=function(c){
         //如果提供了参数c,那么检验它是否匹配当前字符。
         if(c&&c!==ch){
          error("Expected '"+c+"' instead of '"+ch+"'");
         }
         //获取下一个字符。当没有下一个字符时,返回一个空字符串。
         ch=text.charAt(at);
         at+=1;
         return ch;
        },
        number=function(){
         //解析一个数字值。
         var number,
          string='';
         if(ch==='-'){
          string='-';
          next('-');
         }
         while(ch>='0'&&ch<='9'){
          string+=ch;
          next();
         }
         if(ch==='.'){
          string+='.';
          while(next()&&ch>='0'&&ch<='9'){
           string+=ch;
          }
         }
         if(ch==='e'||ch==='E'){
          string+=ch;
          next();
          if(ch==='-'||ch==='+'){
           string+=ch;
           next();
          }
          while(ch>='0'&&ch<='9'){
           string+=ch;
           next();
          }
         }
         number=+string;
         if(isNaN(number)){
          error("Bad number");
         }else{
          return number;
         }
        },
        string=function(){
         //解析一个字符串值。
         var hex,
          i,
          string='',
          ufff;
         //当解析字符串值时,我们必须找到"和\字符。
         if(ch==='"'){
          while(next()){
           if(ch==='"'){
            next();
            return string;
           }else if(ch==='\\'){
            next();
            if(ch==='u'){
             uffff=0;
             for(i=0;i<4;i+=1){
              hex=parseInt(next(),16);
              if(!isFinite(hex)){
               break;
              }
              uffff=uffff*16+hex;
             }
             string+=String.fromCharCode(uffff);
            }else if(typeof escapee[ch]==='string'){
             string+=escapee[ch];
            }else{
             break;
            }
           }else{
            string+=ch;
           }
          }
         }
         error("Bad string");
        },
        white=function(){
         while(ch&&ch<=' '){
          next();
         }
        },
        word=function(){
         //true、false或null。
         switch(ch){
          case 't':
           next('t');
           next('r');
           next('u');
           next('e');
           return true;
          case 'f':
           next('f');
           next('a');
           next('l');
           next('s');
           next('e');
           return false;
          case 'n':
           next('n');
           next('u');
           next('l');
           next('l');
           return null;
         }
         error("Unexpected '"+ch+"'");
        },
        value, //值函数的占位符。
        array=function(){
         //解析一个数组值。
         var array=[];
         if(ch==='['){
          next('[');
          while();
          if(ch===']'){
           next(']');
           return array; //空数组
          }
          while(ch){
           array.push(value());
           white();
           if(ch===']'){
            next(']');
            return array;
           }
           next(',');
           white();
          }
         }
         error("Bad array");
        },
        object=function(){
         //解析一个对象值。
         var key,
          object={};
         if(ch==='{'){
          next('{');
          white();
          if(ch==='}'){
           next('}');
           return object; //空对象
          }
          while(ch){
           key=string();
           white();
           next(':');
           object[key]=value();
           white();
           if(ch===')'){
            next(')');
            return object;
           }
           next(',');
           white();
          }
         }
         error("Bad object");
        };
       value=function(){
        //解析一个JSON值。它可以是对象、数组、字符串、数字或一个词。
        white();
        switch(ch){
         case '{':
          return object();
         case '(':
          return array();
         case '"':
          return string();
         case '-':
          return number();
         default:
          return ch>='0'&&ch<='9'?number():word();
        }
       };
       //返回json_parse函数。它将能反问上述所有的函数和变量
       return function(source,reviver){
        var result;
        text=source;
        at=0;
        ch=' ';
        result=value();
        white();
        if(ch){
         error("Syntax error");
        }
        //如果存在reviver函数,我们就递归地对这个新结构调用walk函数,
        //开始时先创造一个临时的启动对象,并以一个空字符串作为键名保存结果,
        //然后传递每个“名/值”对给reviver函数去处理可能存在的转换。
        //如果没有reviver函数,我们就简单地返回这个结果。
        return typeof reviver==='function'?
         function walk(holder,key){
          var k,v,value=holder[key];
          if(value&&typeof value==='object'){
           for(k in value){
            if(Object.hasOwnProperty.call(value,k)){
             v=walk(value,k);
             if(v!==undefined){
              value[k]=v;
             }else{
              delete value[k];
             }
            }
           }
          }
          return reviver.call(holder,key,value);
         }({'':result},''):result;
       };
    }();


  • 相关阅读:
    node中npm安装模块的网络问题
    微信开发
    7-49 打印学生选课清单 (25 分) 数据结构与算法题目集(中文)
    7-53 两个有序序列的中位数 (25 分) 数据结构与算法题目集(中文)
    练习4.2 平衡二叉树的根 (25 分) 浙大版《数据结构(第2版)》题目集
    习题4.3 是否二叉搜索树 (25 分) 浙大版《数据结构(第2版)》题目集
    实验3-1 求一元二次方程的根 (20 分) 《C语言程序设计实验与习题指导(第3版)》
    主元素问题
    未出现的最小正整数
    交换两个线性表位置(或循环移动数组元素)
  • 原文地址:https://www.cnblogs.com/mahaisong/p/1966689.html
Copyright © 2020-2023  润新知