学习第十一天(2019-11-24)

第十八章 JavaScript与XML

一、浏览器对XML DOM的支持

1、 DOM2级核心

   在支持DOM2级的浏览器中可以使用以下语法来创建一个空白的 XML文档:
       var xmldom = document.implementation.createDocument(namespaceUri, root, doctype);
   要检测浏览器是否支持 DOM2级 XML,可以使用下面这行代码:
       var hasXmlDom = document.implementation.hasFeature("XML", "2.0");

   在实际开发中,很少需要从头开始创建一个 XML 文档,更常见的情况往往是将某个XML文档解析为DOM结构,或者反之。由于 DOM2级规范没有提供这种功能,因此就出现了一些事实标准。

2、DOMParser类型 

   为了将XML解析为 DOM文档,Firefox引入了DOMParser 类型;后来,IE9、Safari、Chrome和 Opera 也支持了这个类型。在解析 XML之前,首先必须创建一个 DOMParser 的实例,然后再调用 parseFromString()方法。

   DOMParser只能解析格式良好的XML,因而不能把 HTML解析为HTML文档。在发生解析错误时,仍然会从 parseFromString()中返回一个Document 对象,但这个对象的文档元素是<parsererror>,而文档元素的内容是对解析错误的描述。

下面是一个例子:

 1 var parser = new DOMParser();
 2 var xmldom = parser.parseFromString("<root><child/></root>", "text/xml");
 3 alert(xmldom.documentElement.tagName); //"root"
 4 alert(xmldom.documentElement.firstChild.tagName); //"child"
 5 var anotherChild = xmldom.createElement("child");
 6 xmldom.documentElement.appendChild(anotherChild);
 7 var children = xmldom.getElementsByTagName("child");
 8 alert(children.length); //2
 9 
10 var parser = new DOMParser(),xmldom,errors;
11 try {
12     //解析出错     
13     xmldom = parser.parseFromString("<root>", "text/xml");
14     errors = xmldom.getElementsByTagName("parsererror");
15     if (errors.length > 0){
16         throw new Error("Parsing error!");     
17     } 
18 } catch (ex) {
19      alert("Parsing error!"); 
20 } 
21  

3、XMLSerializer类型 

   在引入DOMParser的同时,Firefox还引入了 XMLSerializer 类型,提供了相反的功能:将DOM文档序列化为 XML字符串。后来,IE9+、Opera、Chrome和 Safari都支持了XMLSerializer。 

   要序列化DOM文档,首先必须创建XMLSerializer的实例,然后将文档传入其serializeToString()方法,如下面的例子所示:

var serializer = new XMLSerializer();
var xml = serializer.serializeToString(xmldom);
alert(xml)

4、IE8及之前版本中的XML  

 a、在IE中,与其他浏览器不同,IE通过ActiveX对象实现对XML的支持。要创建一个XML文档的实例,要使用ActiveXObject构造函数并为其传入一个表示XML文档版本的字符串。微软推荐使用 MSXML2.DOMDocument.6.0 或 MSXML2.DOMDocument.3.0。

如下:

//尝试创建每个版本的实例并观察是否有错误发生,可以确定哪个版本可用
function createDocument(){
    if (typeof arguments.callee.activeXString != "string"){
        var versions = ["MSXML2.DOMDocument.6.0", "MSXML2.DOMDocument.3.0","MSXML2.DOMDocument"],
            i, len;
        for (i=0,len=versions.length; i < len; i++){
            try {
                new ActiveXObject(versions[i]);
                arguments.callee.activeXString = versions[i];
                break;
            } catch (ex){
                //跳过
            }
        }
    }
    return new ActiveXObject(arguments.callee.activeXString);
}

   b、要解析 XML 字符串,首先必须创建一个DOM文档,然后调用loadXML()方法。新创建的 XML文档完全是一个空文档,因而不能对其执行任何操作。为 loadXML()方法传入的XML字符串经解析之后会被填充到 DOM 文档中,如下。

1 var xmldom = createDocument(); 
2 xmldom.loadXML("<root><child/></root>");
3 alert(xmldom.documentElement.tagName); //"root"
4 alert(xmldom.documentElement.firstChild.tagName); //"child"
5 var anotherChild = xmldom.createElement("child");
6 xmldom.documentElement.appendChild(anotherChild);
7 var children = xmldom.getElementsByTagName("child");
8 alert(children.length); //2

  c、 序列化XML

   IE将序列化 XML 的能力内置在了 DOM 文档中。每个 DOM 节点都有一个 xml 属性,其中保存着表示该节点的 XML 字符串。

   例如:alert(xmldom.xml); 

 d、加载XML

   加载文档的方式也可以分为同步和异步两种。要指定加载文档的方式,可以设置async属性,true表示异步,false表示同步(默认值为true)。在确定了加载XML文档的方式后,调用 load()可以启动下载过程。

  同步加载:

 1 var xmldom = createDocument();
 2 xmldom.async = false;
 3 xmldom.load("example.xml");
 4 if (xmldom.parseError != 0){
 5     //处理错误
 6 } else {
 7     alert(xmldom.documentElement.tagName); //"root"
 8     alert(xmldom.documentElement.firstChild.tagName); //"child"
 9     var anotherChild = xmldom.createElement("child");
10     xmldom.documentElement.appendChild(anotherChild);
11     var children = xmldom.getElementsByTagName("child");
12     alert(children.length); //2
13     alert(xmldom.xml);
14 }

  异步加载:虽然同步方式比较方便,但如果下载时间太长,会导致程序反应很慢。因此,在加载XML文档时,通常都使用异步方式。 在异步加载XML文件的情况下,需要为XML DOM文档的onreadystatechange 事件指定处理程序,有4个就绪状态。

   在实际开发中,要关注的只有一个就绪状态:4。这个状态表示 XML文件已经全部加载完毕,而且已经全部解析为DOM文档。通过 XML文档的readyState属性可以取得其就绪状态。以异步方式加载XML文件的典型模式如下。

 1 var xmldom = createDocument();
 2 xmldom.async = true;
 3 xmldom.onreadystatechange = function(){
 4     if (xmldom.readyState == 4){
 5         if (xmldom.parseError != 0){  //错误处理
 6             alert("An error occurred:\nError Code: "
 7             + xmldom.parseError.errorCode + "\n"
 8             + "Line: " + xmldom.parseError.line + "\n"
 9             + "Line Pos: " + xmldom.parseError.linepos + "\n"
10             + "Reason: " + xmldom.parseError.reason);
11         } else { //处理文档
12             alert(xmldom.documentElement.tagName); //"root"
13             alert(xmldom.documentElement.firstChild.tagName); //"child"
14             var anotherChild = xmldom.createElement("child");
15             xmldom.documentElement.appendChild(anotherChild);
16             var children = xmldom.getElementsByTagName("child");
17             alert(children.length); //2
18             alert(xmldom.xml);
19         }
20     }
21 };
22 xmldom.load("example.xml");

5、跨浏览器处理XML 

  综合上面的代码,就可以得到跨浏览器处理XML的方案。

  下面这个函数可以在所有四种主要浏览器中使用:

//解析 XML 
function parseXml(xml){
    var xmldom = null;
    if (typeof DOMParser != "undefined"){
        xmldom = (new DOMParser()).parseFromString(xml, "text/xml");
        var errors = xmldom.getElementsByTagName("parsererror");
        if (errors.length){
            throw new Error("XML parsing error:" + errors[0].textContent);
        }
    } else if (typeof ActiveXObject != "undefined"){
        xmldom = createDocument();
        xmldom.loadXML(xml);
        if (xmldom.parseError != 0){
            throw new Error("XML parsing error: " + xmldom.parseError.reason);
        }
    } else {
        throw new Error("No XML parser available.");
    }
    return xmldom;
}
 
//序列化 XML
function serializeXml(xmldom){
    if (typeof XMLSerializer != "undefined"){
        return (new XMLSerializer()).serializeToString(xmldom);
    } else if (typeof xmldom.xml != "undefined"){
        return xmldom.xml;
    } else {
        throw new Error("Could not serialize XML DOM.");
    }
}

 

二、浏览器对 XPath的支持 

   XPath是设计用来在DOM文档中查找节点的一种手段,因而对XML处理也很重要。XPath是在DOM3级XPath模块中首次跻身推荐标准行列的。很多浏览器都实现了这个推荐标准,但IE则以自己的方式实现了XPath。

 1、 DOM3级XPath 

  要确定某浏览器是否支持DOM3级XPath,可以使用以下JavaScript代码:
    var supportsXPath = document.implementation.hasFeature("XPath", "3.0");

  在DOM3级XPath规范定义的类型中,最重要的两个类型是XPathEvaluator和XPathResult。XPathEvaluator用于在特定的上下文中对XPath表达式求值。

 a、单节点结果: 指定常量 XPathResult.FIRST_ORDERED_NODE_TYPE 会返回第一个匹配的节点,可以通过结果的 singleNodeValue属性来访问该节点。例如: 

1 var result = xmldom.evaluate("employee/name", xmldom.documentElement, null,
2 XPathResult.FIRST_ORDERED_NODE_TYPE, null);
3 if (result !== null) {
4     alert(result.singleNodeValue.tagName);
5 }

b、简单类型结果:

//如果有节点匹配"employee/name",则 booleanValue 属性的值就是 true
var result = xmldom.evaluate("employee/name", xmldom.documentElement, null,XPathResult.BOOLEAN_TYPE, null);
alert(result.booleanValue);
//计算与给定模式匹配的所有节点数量的 count() var result = xmldom.evaluate("count(employee/name)", xmldom.documentElement,null, XPathResult.NUMBER_TYPE, null); alert(result.numberValue); //对于字符串类型,evaluate()方法会查找与 XPath 表达式匹配的第一个节点,然后返回其第一个子节点的值 var result = xmldom.evaluate("employee/name", xmldom.documentElement, null,XPathResult.STRING_TYPE, null); alert(result.stringValue);

c、默认类型结果: 所有 XPath表达式都会自动映射到特定的结果类型。像前面那样设置特定的结果类型,可以限制表达式的输出。而使用XPathResult.ANY_TYPE 常量可以自动确定返回结果的类型。一般来说,自动选择的结果类型可能是布尔值、数值、字符串值或一个次序不一致的节点迭代器。要确定返回的是什么结果类型,可以检测结果的resultType 属性。

d、对命名空间的支持

对于利用了命名空间的XML文档,XPathEvaluator 必须知道命名空间信息,然后才能正确地进行求值。处理命名空间的方法也不止一种。以下面的XM代码为例。 

 1 <?xml version="1.0" ?>
 2 <wrox:books xmlns:wrox="http://www.wrox.com/">
 3     <wrox:book>
 4         <wrox:title>Professional JavaScript for Web Developers</wrox:title>
 5         <wrox:author>Nicholas C. Zakas</wrox:author>
 6     </wrox:book>
 7     <wrox:book>
 8         <wrox:title>Professional Ajax</wrox:title>
 9         <wrox:author>Nicholas C. Zakas</wrox:author>
10         <wrox:author>Jeremy McPeak</wrox:author>
11         <wrox:author>Joe Fawcett</wrox:author>
12     </wrox:book>
13 </wrox:books>

 在这个XML文档中,所有元素定义都来自 http://www.wrox.com/命名空间,以前缀wrox标识。 如果要对这个文档使用XPath,就需要定义要使用的命名空间;否则求值将会失败。 

 处理命名空间的第一种方法是通过 createNSResolver()来创建 XPathNSResolver 对象:

1 //通过 createNSResolver()来创建 XPathNSResolver 对象。
2 var nsresolver = xmldom.createNSResolver(xmldom.documentElement);
3 var result = xmldom.evaluate("wrox:book/wrox:author",
4             xmldom.documentElement, nsresolver,
5             XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
6 alert(result.snapshotLength);

处理命名空间的第二种方法就是定义一个函数,让它接收一个命名空间前缀,返回关联的 URI:

//定义一个函数,让它接收一个命名空间前缀,返回关联的URI
var nsresolver = function(prefix){
    switch(prefix){
        case "wrox": return "http://www.wrox.com/";
        //其他前缀
    }
};
var result = xmldom.evaluate("count(wrox:book/wrox:author)",
            xmldom.documentElement, nsresolver, XPathResult.NUMBER_TYPE, null);
alert(result.numberValue);

2、IE中的XPath 

  IE对XPath的支持是内置在基于ActiveX的 XML DOM文档对象中的,没有使用DOMParser返回的DOM对象。因此,为了在 IE9及之前的版本中使用XPath,必须使用基于ActiveX的实现。这个接口在每个节点上额外定义了两个的方法:selectSingleNode()和 selectNodes();

 selectSingleNode()方法接受一个XPath模式,在找到匹配节点时返回第一个匹配的节点,如果没有找到匹配的节点就返回null。

 selectNodes()方法也接收一个 XPath模式作为参数,但它返回与模式匹配的所有节点的 NodeList(如果没有匹配的节点,则返回一个包含零项的NodeList)。

var element = xmldom.documentElement.selectSingleNode("employee/name");
if (element !== null){
  alert(element.xml);
}

var elements = xmldom.documentElement.selectNodes("employee/name");
alert(elements.length);

 

 IE对命名空间的支持:要在 IE 中处理包含命名空间的 XPath 表达式,你必须知道自己使用的命名空间,并按照如下格式创建一个字符串:"xmlns:prefix1='uri1' xmlns:prefix2='uri2' xmlns:prefix3='uri3'"

1 xmldom.setProperty("SelectionNamespaces", "xmlns:wrox=’http://www.wrox.com/’");
2 var result = xmldom.documentElement.selectNodes("wrox:book/wrox:author");
3 alert(result.length);

 

3、跨浏览器使用XPath 

  因为IE对XPath功能的支持有限,因此跨浏览器 XPath只能保证达到 IE支持的功能。也就是要在其他使用 DOM3 级 XPath 对象的浏览器中,重新创建 selectSingleNode()和 selectNodes()方法。

selectSingleNode(),它接收三个参数:上下文节点、 XPath表达式和可选的命名空间对象

 1 function selectSingleNode(context, expression, namespaces){
 2     var doc = (context.nodeType != 9 ? context.ownerDocument : context);
 3     if (typeof doc.evaluate != "undefined"){
 4         var nsresolver = null;
 5         if (namespaces instanceof Object){
 6             nsresolver = function(prefix){
 7                 return namespaces[prefix];
 8             };
 9         }
10         var result = doc.evaluate(expression, context, nsresolver,
11             XPathResult.FIRST_ORDERED_NODE_TYPE, null);
12         return (result !== null ? result.singleNodeValue : null);
13     } else if (typeof context.selectSingleNode != "undefined"){
14         //创建命名空间字符串
15         if (namespaces instanceof Object){
16             var ns = "";
17             for (var prefix in namespaces){
18                 if (namespaces.hasOwnProperty(prefix)){
19                     ns += "xmlns:" + prefix + "='" + namespaces[prefix] + "' ";
20                 }
21             }
22             doc.setProperty("SelectionNamespaces", ns);
23         }
24         return context.selectSingleNode(expression);
25     } else {
26         throw new Error("No XPath engine found.");
27     }
28 }
29  
30 var result = selectSingleNode(xmldom.documentElement, "wrox:book/wrox:author",{ wrox: "http://www.wrox.com/" });
31 alert(serializeXml(result));

 selectNodes()函数,接收与selectSingleNode()相同的三个参数,而且大部分逻辑都相似。

 1 function selectNodes(context, expression, namespaces){
 2     var doc = (context.nodeType != 9 ? context.ownerDocument : context);
 3     if (typeof doc.evaluate != "undefined"){
 4         var nsresolver = null;
 5         if (namespaces instanceof Object){
 6             nsresolver = function(prefix){
 7                 return namespaces[prefix];
 8             };
 9         }
10         var result = doc.evaluate(expression, context, nsresolver,
11         XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
12         var nodes = new Array();
13         if (result !== null){
14             for (var i=0, len=result.snapshotLength; i < len; i++){
15                 nodes.push(result.snapshotItem(i));
16             }
17         }
18         return nodes;
19     } else if (typeof context.selectNodes != "undefined"){
20         //创建命名空间字符串
21         if (namespaces instanceof Object){
22             var ns = "";
23             for (var prefix in namespaces){
24                 if (namespaces.hasOwnProperty(prefix)){
25                     ns += "xmlns:" + prefix + "='" + namespaces[prefix] + "' ";
26                 }
27             }
28             doc.setProperty("SelectionNamespaces", ns);
29         }
30         var result = context.selectNodes(expression);
31         var nodes = new Array();
32         for (var i=0,len=result.length; i < len; i++){
33             nodes.push(result[i]);
34         }
35         return nodes;
36     } else {
37         throw new Error("No XPath engine found.");
38     }
39 }
40  
41 var result = selectNodes(xmldom.documentElement, "wrox:book/wrox:author",{ wrox: "http://www.wrox.com/" });
42 alert(result.length);

 

三、浏览器对 XSLT的支持 

   XSLT是与XML相关的一种技术,它利用XPath将文档从一种表现形式转换成另一种表现形式,XML和XPath不同,XSLT没有正式的 API,只能依靠浏览器开发商以自己的方式来实现它。

1、IE中的XSLT

  a、简单的XSLT转换 

       使用XSLT样式表转换XML文档的最简单方式,就是将它们分别加到一个DOM文档中,然后再使用transformNode()方法

  b、复杂的XSLT转换

       虽然 transformNode()方法提供了基本的 XSLT转换能力,但还有使用这种语言的更复杂的方式。 为此,必须要使用XSL模板和 XSL处理器。

2、XSLTProcessor类型 

   Mozilla通过在Firefox中创建新的类型,实现了JavaScript对XSLT的支持。开发人员可以通过XSLTProcessor类型使用XSLT转换 XML文档,其方式与在IE中使用 XSL处理器类似。

3、跨浏览器使用XSLT 

   IE对XSLT转换的支持与XSLTProcessor的区别实在太大,因此要想重新实现二者所有这方面的功能并不现实。因此,跨浏览器兼容性最好的 XSLT转换技术,只能是返回结果字符串,下面这个函数可以在 IE、Firefox、Chrome、Safari和 Opera中使用。

 1 function transform(context, xslt){
 2     if (typeof XSLTProcessor != "undefined"){
 3         var processor = new XSLTProcessor();
 4         processor.importStylesheet(xslt);
 5         var result = processor.transformToDocument(context);
 6         return (new XMLSerializer()).serializeToString(result);
 7     } else if (typeof context.transformNode != "undefined") {
 8         return context.transformNode(xslt);
 9     } else {
10         throw new Error("No XSLT processor available.");
11     }
12 }

 

第十九章 E4X

   E4X是以ECMA-357标准的形式发布的对 ECMAScript的一个扩展。E4X的目的是为操作XML数据提供与标准ECMAScript更相近的语法。

    E4X具有下列特征:

          1、E4X只用一个类型来表示 XML中的各种节点。

          2、XML 对象中封装了对所有节点都有用的数据和行为。为表现多个节点的集合,这个规范定义了 XMLList 类型  。

          3、Namespace 和 QName,分别表现命名空间和限定名。

          4、为便于查询 XML结构,E4X还修改了标准了的 ECMAScript语法,如:使用两个点(..)表示要匹配所有后代元素,使用@字符表示应该返回一或多个特性。星号字符(*)是一个通配符,可以匹配任意类型的节点。 所有这些查询都可以通过一组执行相同操作的方法来实现。

    到2011年底,Firefox还是唯一一个支持E4X的浏览器,很多浏览器基本没有实现,现在开发中也用得很少,所以这一章只简单了解。

 

第二十章 JSON

   JSON是一个轻量级的数据格式,可以简化表示复杂数据结构的工作量。JSON使用JavaScript语法的子集表示对象、数组、字符串、数值、布尔值和null。即使 XML也能表示同样复杂的数据结果,但JSON没有那么烦琐,而且在JavaScript中使用更便利。

  一、语法

  1、简单值

    最简单的JSON 数据形式就是简单值。如数值 5,字符串 "Hello world!"。JavaScript字符串与JSON字符串的最大区别在于,JSON 字符串必须使用双引号。

  2、对象

  JSON中对象的属性必须加双引号,这在JSON中是必需的。属性的值可以是简单值,也可以是复杂类型值,因此可以像下面这样在对象中嵌入对象: 

{
    "name": "Nicholas",
    "age": 29,
    "school": {
        "name": "Merrimack College",
        "location": "North Andover, MA"
    }
}

  3、数组

  JavaScript中的数组字面量:
         var values = [25, "hi", true];
在JSON中,可以采用同样的语法表示同一个数组:(注意没有变量和分号) 
     如:     [25, "hi", true]

二、解析与序列化

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

1 var book = {
2         title: "Professional JavaScript",
3         authors: [
4             "Nicholas C. Zakas"
5         ],
6         edition: 3,
7         year: 2011
8        };
9 var jsonText = JSON.stringify(book);

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

  {"title":"Professional JavaScript","authors":["Nicholas C. Zakas"],"edition":3, "year":2011} 

将JSON字符串直接传递给 JSON.parse()就可以得到相应的 JavaScript值。例如,使用下列代码 就可以创建与book 类似的对象:
     var bookCopy = JSON.parse(jsonText);

2、序列化选项 

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

a、如果过滤器参数是数组,那么JSON.stringify()的结果中将只包含数组中列出的属性,如下:

var book = {
        "title": "Professional JavaScript",
        "authors": [
            "Nicholas C. Zakas"
        ],
        edition: 3,
        year: 2011
    };
//{"title":"Professional JavaScript","edition":3} 
var jsonText = JSON.stringify(book, ["title", "edition"]);

b、传入的函数接收两个参数,属性(键)名和属性值。根据属性(键)名可以知道应该如何处理要序列化的对象中的属性。如果函数返回了undefined,那么相应的属性会被忽略。

 1 var book = {
 2         "title": "Professional JavaScript",
 3         "authors": [
 4             "Nicholas C. Zakas"
 5         ],
 6         edition: 3,
 7         year: 2011
 8     };
 9 var jsonText = JSON.stringify(book, function(key, value){
10         switch(key){
11             case "authors":
12                 return value.join(",")
13             case "year":
14                 return 5000;
15             case "edition":
16                 return undefined;
17             default:
18                 return value;
19         }
20     });

  序列化后的 JSON字符串如下所示: 

    {"title":"Professional JavaScript","authors":"Nicholas C. Zakas","year":5000} 

 3、字符串缩进

   JSON.stringify()方法的第三个参数用于控制结果中的缩进和空白符。如果这个参数是一个数值,那它表示的是每个级别缩进的空格数。

4、toJSON()方法

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

  可以为任何对象添加 toJSON()方法,比如: 

 1 var book = {
 2         "title": "Professional JavaScript",
 3         "authors": [
 4             "Nicholas C. Zakas"
 5         ],
 6         edition: 3,
 7         year: 2011,
 8         toJSON: function(){
 9             return this.title;
10         }
11     };
12 var jsonText = JSON.stringify(book);

 以上代码在 book 对象上定义了一个 toJSON()方法,该方法返回图书的书名。

toJSON()可以作为函数过滤器的补充,假设把一个对象传入JSON.stringify(),序列化该对象的顺序如下:(1)、如果存在toJSON()方法而且能通过它取得有效的值,则调用该方法。否则,返回对象本身。 (2)、如果提供了第二个参数,应用这个函数过滤器。传入函数过滤器的值是第(1)步返回的值。 (3)、对第(2)步返回的每个值进行相应的序列化。 (4)、如果提供了第三个参数,执行相应的格式化。 

5、 解析选项 

  JSON.parse()方法也可以接收另一个参数,该参数是一个函数,将在每个键值对儿上调用,这个函数被称为还原函数。如果还原函数返回undefined,则表示要从结果中删除相应的键;如果返回其他值,则将该值插入到结果中。

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

 1 var book = {
 2         "title": "Professional JavaScript",
 3         "authors": [
 4             "Nicholas C. Zakas"
 5         ],
 6         edition: 3,
 7         year: 2011,
 8         releaseDate: new Date(2011, 11, 1)
 9     };
10 var jsonText = JSON.stringify(book);
11 var bookCopy = JSON.parse(jsonText, function(key, value){
12         if (key == "releaseDate"){
13             return new Date(value);
14         } else {
15             return value;
16         }
17     });
18 alert(bookCopy.releaseDate.getFullYear());

  以上代码book对象有一个releaseDate属性,该属性保存着一个Date对象。这个对象在经过序列化之后变成了有效的JSON字符串,然后经过解析又在bookCopy中还原为一个Date对象。还原函数在遇到"releaseDate"键时,会基于相应的值创建一个新的Date对象。结果就是bookCopy.releaseDate属性中会保存一个 Date 对象。正因为如此,才能基于这个对象调用getFullYear()方法,如果不这样bookCopy.releaseDate属性中只是一个字符串,不是Date对象。

posted @ 2019-11-24 21:57  xiongbing  阅读(272)  评论(0编辑  收藏  举报