JSON2 源代码

/*
    json2.js
    2014-02-04

    Public Domain.

    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.

    See http://www.JSON.org/js.html


    This code should be minified before deployment.
    See http://javascript.crockford.com/jsmin.html

    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
    NOT CONTROL.


    This file creates a global JSON object containing two methods: stringify
    and parse.

        JSON.stringify(value, replacer, space)
            value       any JavaScript value, usually an object or array.

            replacer    an optional parameter that determines how object
                        values are stringified for objects. It can be a
                        function or an array of strings.

            space       an optional parameter that specifies the indentation
                        of nested structures. If it is omitted, the text will
                        be packed without extra whitespace. If it is a number,
                        it will specify the number of spaces to indent at each
                        level. If it is a string (such as '\t' or ' '),
                        it contains the characters used to indent at each level.

            This method produces a JSON text from a JavaScript value.

            When an object value is found, if the object contains a toJSON
            method, its toJSON method will be called and the result will be
            stringified. A toJSON method does not serialize: it returns the
            value represented by the name/value pair that should be serialized,
            or undefined if nothing should be serialized. The toJSON method
            will be passed the key associated with the value, and this will be
            bound to the value

            For example, this would serialize Dates as ISO strings.

                Date.prototype.toJSON = function (key) {
                    function f(n) {
                        // Format integers to have at least two digits.
                        return n < 10  '0' + n : n;
                    }

                    return this.getUTCFullYear()   + '-' +
                         f(this.getUTCMonth() + 1) + '-' +
                         f(this.getUTCDate())      + 'T' +
                         f(this.getUTCHours())     + ':' +
                         f(this.getUTCMinutes())   + ':' +
                         f(this.getUTCSeconds())   + 'Z';
                };

            You can provide an optional replacer method. It will be passed the
            key and value of each member, with this bound to the containing
            object. The value that is returned from your method will be
            serialized. If your method returns undefined, then the member will
            be excluded from the serialization.

            If the replacer parameter is an array of strings, then it will be
            used to select the members to be serialized. It filters the results
            such that only members with keys listed in the replacer array are
            stringified.

            Values that do not have JSON representations, such as undefined or
            functions, will not be serialized. Such values in objects will be
            dropped; in arrays they will be replaced with null. You can use
            a replacer function to replace those with JSON values.
            JSON.stringify(undefined) returns undefined.

            The optional space parameter produces a stringification of the
            value that is filled with line breaks and indentation to make it
            easier to read.

            If the space parameter is a non-empty string, then that string will
            be used for indentation. If the space parameter is a number, then
            the indentation will be that many spaces.

            Example:

            text = JSON.stringify(['e', {pluribus: 'unum'}]);
            // text is '["e",{"pluribus":"unum"}]'


            text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
            // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'

            text = JSON.stringify([new Date()], function (key, value) {
                return this[key] instanceof Date ?
                    'Date(' + this[key] + ')' : value;
            });
            // text is '["Date(---current time---)"]'


        JSON.parse(text, reviver)
            This method parses a JSON text to produce an object or array.
            It can throw a SyntaxError exception.

            The optional reviver parameter is a function that can filter and
            transform the results. It receives each of the keys and values,
            and its return value is used instead of the original value.
            If it returns what it received, then the structure is not modified.
            If it returns undefined then the member is deleted.

            Example:

            // Parse the text. Values that look like ISO date strings will
            // be converted to Date objects.

            myData = JSON.parse(text, function (key, value) {
                var a;
                if (typeof value === 'string') {
                    a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
                    if (a) {
                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
                            +a[5], +a[6]));
                    }
                }
                return value;
            });

            myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
                var d;
                if (typeof value === 'string' &&
                        value.slice(0, 5) === 'Date(' &&
                        value.slice(-1) === ')') {
                    d = new Date(value.slice(5, -1));
                    if (d) {
                        return d;
                    }
                }
                return value;
            });


    This is a reference implementation. You are free to copy, modify, or
    redistribute.
*/

/*jslint evil: true, regexp: true */

/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
    call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
    lastIndex, length, parse, prototype, push, replace, slice, stringify,
    test, toJSON, toString, valueOf
*/


/*-----↑- 这是用谷歌翻译了上面的,有很多不准确的地方,大家也可自行翻译---↑-----*/
/* 
    json2.js 
    2014年2月4日 

    公共领域。 

    任何明示或暗示的保证。使用时需自行承担风险。 

    见http://www.JSON.org/js.html 


    这段代码应该在部署之前压缩。 
    见http://javascript.crockford.com/jsmin.html 

    使用自己的拷贝。这是非常不明智的加载代码来自服务器的你 
    无法控制。 


    该文件创建一个包含两个方法的全局JSON对象:字符串化 
    和解析。 

        JSON.stringify(价值,替代品,空间) 
          珍惜任何JavaScript值,通常是一个对象或数组。 

            替换器一个可选的参数,它决定了对象 
                     值字符串化的对象。它可以是一个 
                        函数或一个字符串数组。 

               空间中的可选参数,指定缩进 
                     嵌套结构。如果它被省略,文本将 
                       没有多余的空格进行包装。如果它是一个数字, 
                          它将指定的空格数来缩进在每 
            水平。如果它是一个字符串(例如'\ t'或''), 
                        它包含了用于缩进在每个级别的人物。 

            这种方法产生的一个JavaScript值的JSON文本。 

            当一个对象的值被发现,如果对象包含的toJSON 
            方法,它的toJSON方法将被调用,其结果将是 
            字符串化。一个的toJSON方法不序列化:它返回 
            由应序列名称/值对代表的价值, 
            或不确定的,如果没有什么应该被序列化。该方法的toJSON 
            将被传递与该值相关联的密钥,这将是 
            绑定到值 

            例如,这将序列日期为ISO字符串。 



        Date.prototype.toJSON = function (key) {
                    function f(n) {
                        // Format integers to have at least two digits.
            //---格式的整数至少有两位。 
                        return n < 10  '0' + n : n;
                    }

                    return this.getUTCFullYear()   + '-' +
                         f(this.getUTCMonth() + 1) + '-' +
                         f(this.getUTCDate())      + 'T' +
                         f(this.getUTCHours())     + ':' +
                         f(this.getUTCMinutes())   + ':' +
                         f(this.getUTCSeconds())   + 'Z';
                };

            你可以提供一个可选的替代品的方法。它会通过 
            键和每个成员的价值,与此结合到含 
            对象。从你的方法返回的值将是 
            序列化。如果你的方法返回undefined,则该成员将 
            被排除在序列化。 

            如果替代品的参数是一个字符串数组,那么这将是 
            用来选择要序列化的成员。它过滤结果 
            这样的替代品数组中列出的键只有成员 
            字符串化。 

            没有JSON的表示,如未定义或价值 
            功能,将不被序列化。在对象这样的值将是 
            下降;在数组中,他们将被替换为空。您可以使用 
            一个替代品的功能,以取代那些使用JSON值。 
            JSON.stringify(未定义)返回undefined。 

            可选的空间参数产生的一个字符串化 
            这是充满了换行和缩进,使其价值 
            更易于阅读。 

            如果空间参数是一个非空字符串,则该字符串将 
            用于缩进。如果空间参数是一个号码,然后 
            缩进将是很多的空间。 

            例如: 


            text = JSON.stringify(['e', {pluribus: 'unum'}]);
            // text is '["e",{"pluribus":"unum"}]'

            text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
            // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'

            text = JSON.stringify([new Date()], function (key, value) {
                return this[key] instanceof Date ?
                    'Date(' + this[key] + ')' : value;
            });
            // text is '["Date(---current time---)"]'
            

        JSON.parse(文字,齐磊) 
            此方法分析一个JSON文本,以生成一个对象或数组。 
            它可以抛出一个SyntaxError异常。 

            可选的齐磊参数是一个能过滤功能, 
            变换的结果。它接收每个键和值, 
            并且其返回值被用来代替原来的值。 
            如果它返回它接收什么,则结构不会被修改。 
            如果它返回undefined,则该成员将被删除。 

            例如: 

            //解析文本。看起来像ISO日期字符串值将 
            //转换为Date对象。 

            myData = JSON.parse(text, function (key, value) {
                var a;
                if (typeof value === 'string') {
                    a =
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
                    if (a) {
                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
                            +a[5], +a[6]));
                    }
                }
                return value;
            });

            myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
                var d;
                if (typeof value === 'string' &&
                        value.slice(0, 5) === 'Date(' &&
                        value.slice(-1) === ')') {
                    d = new Date(value.slice(5, -1));
                    if (d) {
                        return d;
                    }
                }
                return value;
            });


    这是一个参考实现。你可以自由复制,修改,或 
    重新分配。 
*/ 

/* JSLint的邪恶:真,正则表达式:真*/ 

/*员“”,“\ B”,“\ t”的,“\ n”,“\ F”,“\ r”开始“\”“,JSON,”\ \“,适用, 
    打电话,charCodeAt,GETUTCDATE,getUTCFullYear,getUTCHours,
    getUTCMinutes,getUTCMonth将,getUTCSeconds,hasOwnProperty方法,加盟, 
    lastIndex的,长度,分析,样机,推,替换,切片,字符串化, 
    测试的toJSON,的toString,调用valueOf 
*/
/*---------------------------------------------------------------*/




// Create a JSON object only if one does not already exist. We create the
// methods in a closure to avoid creating global variables.
//---创建一个JSON对象只有一个不存在。我们创建了一个闭包的方法来避免创建全局变量。

if (typeof JSON !== 'object') {
    JSON = {};
}

(function () {
    'use strict';

    function f(n) {
        // Format integers to have at least two digits.
        //格式的整数至少有两位。
        return n < 10  '0' + n : n;
    }

    if (typeof Date.prototype.toJSON !== 'function') {

        Date.prototype.toJSON = function () {

            return isFinite(this.valueOf())
                 this.getUTCFullYear()     + '-' +
                    f(this.getUTCMonth() + 1) + '-' +
                    f(this.getUTCDate())      + 'T' +
                    f(this.getUTCHours())     + ':' +
                    f(this.getUTCMinutes())   + ':' +
                    f(this.getUTCSeconds())   + 'Z'
                : null;
        };

        String.prototype.toJSON      =
            Number.prototype.toJSON  =
            Boolean.prototype.toJSON = function () {
                return this.valueOf();
            };
    }

    var cx,
        escapable,
        gap,
        indent,
        meta,
        rep;


    function quote(string) {

// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.
//如果字符串不包含任何控制字符,没有引号,也没有反斜杠字符,那么我们就可以放心地拍它周围的一些报价。否则,我们也必须更换安全转义序列违规字符。

        escapable.lastIndex = 0;
        return escapable.test(string)  '"' + string.replace(escapable, function (a) {
            var c = meta[a];
            return typeof c === 'string'
                 c
                : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
        }) + '"' : '"' + string + '"';
    }


    function str(key, holder) {

// Produce a string from holder[key].
//从持有人[关键]产生的字符串。

        var i,          // The loop counter.//---循环计数器。
            k,          // The member key.//---成员键。
            v,          // The member value.//---该成员值。
            length,
            mind = gap,
            partial,
            value = holder[key];

// If the value has a toJSON method, call it to obtain a replacement value.
//---如果该值有一个的toJSON方法,调用它来获取一个替换值。
        if (value && typeof value === 'object' &&
                typeof value.toJSON === 'function') {
            value = value.toJSON(key);
        }

// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.
//---如果我们调用一个替代品的功能,然后调用替代品,以获取替换值。

        if (typeof rep === 'function') {
            value = rep.call(holder, key, value);
        }

// What happens next depends on the value's type.
//接下来会发生什么取决于值的类型。
        switch (typeof value) {
        case 'string':
            return quote(value);

        case 'number':

// JSON numbers must be finite. Encode non-finite numbers as null.
//JSON的号码必须是有限的。编码非有限数为空。

            return isFinite(value)  String(value) : 'null';

        case 'boolean':
        case 'null':

// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.
//如果该值是一个布尔值或空值,将其转换为字符串。注意:typeof运算空不产生'空'。目前,此案在这里偏远的机会,这一天被定包括在内。

            return String(value);

// If the type is 'object', we might be dealing with an object or an array or
// null.
//---如果类型是'对象',我们可能要处理的对象或数组或者为null。

        case 'object':

// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.
//---由于在ECMAScript中的规范失误的typeof null是“对象”,所以,要当心这种情况下。

            if (!value) {
                return 'null';
            }

// Make an array to hold the partial results of stringifying this object value.
//做一个数组来保存这个字符串化对象值的部分结果。
            gap += indent;
            partial = [];

// Is the value an array?
//---该值是一个数组?

            if (Object.prototype.toString.apply(value) === '[object Array]') {

// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.
//---该值是一个数组。字符串化的每一个元素。使用NULL作为一个占位符,非JSON的值。

                length = value.length;
                for (i = 0; i < length; i += 1) {
                    partial[i] = str(i, value) || 'null';
                }

// Join all of the elements together, separated with commas, and wrap them in
// brackets.
//---加入所有元素结合在一起,以逗号分隔,并包装在括号内。

                v = partial.length === 0
                     '[]'
                    : gap
                     '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
                    : '[' + partial.join(',') + ']';
                gap = mind;
                return v;
            }

// If the replacer is an array, use it to select the members to be stringified.
//---如果替代品是一个数组,用它来选择要字符串化的成员。
            if (rep && typeof rep === 'object') {
                length = rep.length;
                for (i = 0; i < length; i += 1) {
                    if (typeof rep[i] === 'string') {
                        k = rep[i];
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (gap  ': ' : ':') + v);
                        }
                    }
                }
            } else {

// Otherwise, iterate through all of the keys in the object.
//---否则,遍历所有对象中的键。

                for (k in value) {
                    if (Object.prototype.hasOwnProperty.call(value, k)) {
                        v = str(k, value);
                        if (v) {
                            partial.push(quote(k) + (gap  ': ' : ':') + v);
                        }
                    }
                }
            }

// Join all of the member texts together, separated with commas,
// and wrap them in braces.
//---加入所有成员文本在一起,用逗号分隔,并包装在大括号。

            v = partial.length === 0
                 '{}'
                : gap
                 '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
                : '{' + partial.join(',') + '}';
            gap = mind;
            return v;
        }
    }

// If the JSON object does not yet have a stringify method, give it one.
//---如果JSON对象还没有一个字符串化的方法,给它一次。
    if (typeof JSON.stringify !== 'function') {
        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
        meta = {    // table of character substitutions //---表中的字符替换
            '\b': '\\b',
            '\t': '\\t',
            '\n': '\\n',
            '\f': '\\f',
            '\r': '\\r',
            '"' : '\\"',
            '\\': '\\\\'
        };
        JSON.stringify = function (value, replacer, space) {

// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.
//---该字符串化方法接受一个值和一个可选的替代品,和一个可选的空间参数,并返回一个JSON文本。的替代品可以是一个函数,它可以替代值或字符串将选择键的数组。
//可以提供一个默认的替代品的方法。利用空间参数可产生文本更容易阅读。

            var i;
            gap = '';
            indent = '';

// If the space parameter is a number, make an indent string containing that
// many spaces.
//---如果空间参数是一个数字,使含有很多空格缩进字符串。

            if (typeof space === 'number') {
                for (i = 0; i < space; i += 1) {
                    indent += ' ';
                }

// If the space parameter is a string, it will be used as the indent string.
//---如果空间参数是一个字符串,它将被用作缩进字符串。
            } else if (typeof space === 'string') {
                indent = space;
            }

// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.
//---如果有一个替代物,它必须是一个函数或数组。
//---否则,抛出一个错误。

            rep = replacer;
            if (replacer && typeof replacer !== 'function' &&
                    (typeof replacer !== 'object' ||
                    typeof replacer.length !== 'number')) {
                throw new Error('JSON.stringify');
            }

// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.
//---使载有''的关键我们的价值是假的根对象。
//---字符串化返回值的结果。

            return str('', {'': value});
        };
    }


// If the JSON object does not yet have a parse method, give it one.
//---如果JSON对象还没有一个分析方法,给它一次。
    if (typeof JSON.parse !== 'function') {
        cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
        JSON.parse = function (text, reviver) {

// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.
//---parse方法接受一个文本和一个可选的齐磊函数,并返回一个JavaScript值,如果文本是一个有效的JSON文本。
            var j;

            function walk(holder, key) {

// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.
//---步行方法用于递归遍历所得到的结构,使变形可制成。

                var k, v, value = holder[key];
                if (value && typeof value === 'object') {
                    for (k in value) {
                        if (Object.prototype.hasOwnProperty.call(value, k)) {
                            v = walk(value, k);
                            if (v !== undefined) {
                                value[k] = v;
                            } else {
                                delete value[k];
                            }
                        }
                    }
                }
                return reviver.call(holder, key, value);
            }


// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.
//---解析发生在四个阶段。在第一阶段,我们替换使用转义序列一定nicode字符。JavaScript的处理多字不正确,要么默默地删除它们,或者将它们视为行结尾。

            text = String(text);
            cx.lastIndex = 0;
            if (cx.test(text)) {
                text = text.replace(cx, function (a) {
                    return '\\u' +
                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
                });
            }

// In the second stage, we run the text against regular expressions that look
// for non-JSON patterns. We are especially concerned with '()' and 'new'
// because they can cause invocation, and '=' because it can cause mutation.
// But just to be safe, we want to reject all unexpected forms.
//---在第二阶段,我们对执行正则表达式查找非JSON模式的文本。我们特别关注'()'和'新',因为它们会导致调用,和'=',因为它可能会导致基因突变。但为了安全起见,我们要拒绝所有意想不到的形式。

// We split the second stage into 4 regexp operations in order to work around
// crippling inefficiencies in IE's and Safari's regexp engines. First we
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
// replace all simple value tokens with ']' characters. Third, we delete all
// open brackets that follow a colon or comma or that begin the text. Finally,
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
//---我们为了解决在IE及Safari的正则表达式引擎瘫痪低效分裂第二阶段为4的正则表达式操作。首先,我们更换的JSON反斜杠对以'@'(非JSON字符)。其次,我们与全部更换简单值令牌']'字符。第三,我们删除跟随一个冒号或逗号或执行文本,所有打开的括号内。最后,我们期待看到剩余的字符只有空格或']'或','或':'或'{'或'}'。如果是这样,那么文字是安全的EVAL。

            if (/^[\],:{}\s]*$/
                    .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
                        .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
                        .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {

// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.
//---在第三阶段,我们使用eval函数将文本编译成JavaScript的结构。在'{'操作须在JavaScript的语法歧义:它可以开始一个块或对象文本。我们总结的文字括号来消除歧义。

                j = eval('(' + text + ')');

// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.
//---在可选的第四个阶段,我们递归遍历这个新结构,将每个名称/值对的齐磊功能可能转变。
                return typeof reviver === 'function'
                     walk({'': j}, '')
                    : j;
            }

// If the text is not JSON parseable, then a SyntaxError is thrown.
//---如果文字不是JSON解析的,那么一个SyntaxError异常。
            throw new SyntaxError('JSON.parse');
        };
    }
}());

 

posted @ 2014-06-30 19:40  阿凡同学  阅读(359)  评论(0编辑  收藏  举报