zoukankan      html  css  js  c++  java
  • json2.js 源码解读

    这一部分是对Date String Number Boolean扩展toString方法,Date的toString是返回UTC格式的字符串,而后面几个是返回原始值。

            function f(n) {// 返回两位数字字符串
                return n < 10 ? '0' + n: n;
            }
            if (typeof Date.prototype.toJSON !== 'function') {//如果Date不支持原生的toJSON方法
                Date.prototype.toJSON = function() {//扩展Date的toJSON方法
                    //是否是有穷数,如果为true,返回根据UTC时间计算出的年月日时分秒 YYYY-MM-DDThh:mm:ssZ如果为false,返回null
                    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 Number Boolean的toJSON方法
                String.prototype.toJSON = Number.prototype.toJSON = Boolean.prototype.toJSON = function() {
                    return this.valueOf();//返回他们的原始值
                };
            }

    这里是扩展Stringify方法

    if (typeof JSON.stringify !== 'function') {//扩展JSON的stringify方法
        escapable = /[\"x00-x1fx7f-x9fu00adu0600-u0604u070fu17b4u17b5u200c-u200fu2028-u202fu2060-u206fufeffufff0-uffff]/g;
        meta = { // table of character substitutions
            '': '\b',
            '	': '\t',
            '
    ': '\n',
            'f': '\f',
            '
    ': '\r',
            '"': '\"',
            '\': '\\'
        };
        JSON.stringify = function(value, replacer, space) {//扩展JSON.stringify方法
            var i;//for循环变量
            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) {//分隔符为space个空格
                    indent += ' ';
                }
    
            } else if (typeof space === 'string') {//如果是字符串
                indent = space;//分隔符就是字符串
            }
    
            rep = replacer;
            if (replacer && typeof replacer !== 'function' && (typeof replacer !== 'object' || typeof replacer.length !== 'number')) {
                throw new Error('JSON.stringify');//如果第二个参数存在,必须为函数或者数组(伪数组),否则抛出异常
            }
    
            return str('', {
                '': value
            });
        };
    }

    做了2件事:获取分隔符和replacer,内部调用str方法

            function str(key, holder) {//第一次调用时 key:'', holder:{'': value} 
                var i, // The loop counter.
                k, // The member key.
                v, // The member value.
                length, mind = gap,//初始mind和gap都为""
                partial, value = holder[key];//第二次调用时 value就是传入的键所对应的值
                //如果value有toJSON方法
                if (value && typeof value === 'object' && typeof value.toJSON === 'function') {
                    value = value.toJSON(key);//调用value.toJSON方法
                }
    
                if (typeof rep === 'function') {//如果replace是一个方法
                    value = rep.call(holder, key, value);
                }
                // 判断value类型
                switch (typeof value) {
                case 'string'://如果是字符串,加引号
                    return quote(value);
                case 'number'://如果是数值
                    //有穷数用原生的String()将数值转为符串,否则返回null
                    return isFinite(value) ? String(value) : 'null';
                case 'boolean'://如果是bool值或者null,返回String(value)
                case 'null':
                    return String(value);
                case 'object'://如果是对象
                    if (!value) {//null
                        return 'null';
                    }
                    gap += indent;//分隔符
                    partial = [];//临时数组
                    if (Object.prototype.toString.apply(value) === '[object Array]') {//数组
                        length = value.length;
                        for (i = 0; i < length; i += 1) {//对数组的每一项递归调用str
                            partial[i] = str(i, value) || 'null';
                        }
                        // 如果partial为[],返回"[]"
                        // 如果 gap分隔符存在,返回[
    ' + gap + partial.join(',
    ' + gap) + '
    ' + mind + ']'
                        // 如果分隔符不存在,返回'[' + partial.join(',') + ']'
                        v = partial.length === 0 ? '[]': gap ? '[
    ' + gap + 
                        partial.join(',
    ' + gap) + '
    ' + mind + ']': '[' + partial.join(',') + ']';
                        gap = mind;//重置为""
                        return v;
                    }
                    if (rep && typeof rep === 'object') {//如果rep存在且为数组或者对象
                        length = rep.length;//如果是数组
                        for (i = 0; i < length; i += 1) {//过滤
                            if (typeof rep[i] === 'string') {
                                k = rep[i];//键是数组的值
                                v = str(k, value);//递归调用
                                if (v) {
                                    //"key": value 或者"key":value
                                    partial.push(quote(k) + (gap ? ': ': ':') + v);
                                }
                            }
                        }
                    } else {//如果不是数组或方法或不存在
                        for (k in value) {
                            if (Object.prototype.hasOwnProperty.call(value, k)) {
                                v = str(k, value);
                                if (v) {
                                    partial.push(quote(k) + (gap ? ': ': ':') + v);
                                }
                            }
                        }
                    }
    
                    v = partial.length === 0 ? '{}': gap ? '{
    ' + gap + 
                    partial.join(',
    ' + gap) + '
    ' + mind + '}': '{' + partial.join(',') + '}';
                    gap = mind;
                    return v;
                }
            }

    下面是图解:

            function quote(string) {//将传入的字符串加上引号,有必要转义的先转义
                escapable.lastIndex = 0;//起始位置从0开始
                return escapable.test(string) ? '"' + string.replace(escapable,
                function(a) {//匹配到的字符 如	 
    
                    var c = meta[a];//字符对应的转义表示
                    //如果c是字符串 ,直接返回对象中键所对应的值  '	'=>'\t'
                    //如果c不是字符串,也就是说它不在meta对象中,这时做不同的转义处理:
                    //拿 a为"u0600"举例
                    //a.charCodeAt(0) =>1536
                    //a.charCodeAt(0).toString(16) => 600
                    //('0000' + a.charCodeAt(0).toString(16)) =>0000600
                    //('0000' + a.charCodeAt(0).toString(16)).slice( - 4) 取最后四位 => 0600
                    //'\u' + ('0000' + a.charCodeAt(0).toString(16)).slice( - 4)) '\u0600'
                    return typeof c === 'string' ? c: '\u' + ('0000' + a.charCodeAt(0).toString(16)).slice( - 4);
                }) + '"': '"' + string + '"';
            }

     这里是扩展parse方法

            if (typeof JSON.parse !== 'function') {//如果JSON没有parse方法
                cx = /[u0000u00adu0600-u0604u070fu17b4u17b5u200c-u200fu2028-u202fu2060-u206fufeffufff0-uffff]/g;
                JSON.parse = function(text, reviver) {//扩展JSON方法
                    var j;
    
                    function walk(holder, key) {// walk({'':j},'')
    
                        var k, v, value = holder[key];//value第一次是传入的eval编译后的结果
                        if (value && typeof value === 'object') {//如果value存在并且是对象
                            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];
                                    }
                                }
                            }
                        }
                        //调用walk之前有判断,所以在这里reviver肯定存在
                        return reviver.call(holder, key, value);
                    }
                    text = String(text);
                    cx.lastIndex = 0;
                    if (cx.test(text)) {
                        text = text.replace(cx,
                        function(a) {
                            // u0600   --->  \u0600 因为需要转义
                            return '\u' + ('0000' + a.charCodeAt(0).toString(16)).slice( - 4);
                        });
                    }
    
                    // text.replace(/\(?:["\/bfnrt]|u[0-9a-fA-F]{4})/g, '@') 
                    // =>把\t \uffff 这类转为@
                    // =>var text='{"a":"\t44","b":"\uffff"}';  text.replace(/\(?:["\/bfnrt]|u[0-9a-fA-F]{4})/g, '@');  //{"a":"@44","b":"@"}
                    // replace(/"[^"\
    
    ]*"|true|false|null|-?d+(?:.d*)?(?:[eE][+-]?d+)?/g, ']')
                    // =>把非空字符串、数值、bool、null替换为]
                    // .replace(/(?:^|:|,)(?:s*[)+/g, '')
                    // => 把 [   ,[    :[  这类的替换为''
                    // 如果剩余的字符串只剩下 ]:,{}和空格 就是测试通过,否则抛出异常
                    if (/^[],:{}s]*$/.test(text.replace(/\(?:["\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
    .replace(/"[^"\ ]*"|true|false|null|-?d+(?:.d*)?(?:[eE][+-]?d+)?/g, ']').replace(/(?:^|:|,)(?:s*[)+/g, ''))) { j = eval('(' + text + ')');//eval()传入的参数加括号编译 return typeof reviver === 'function' ? walk({//如果第二个参数是函数 返回walk({'':j},'')的结果,否则直接返回eval编译的结果 '': j }, '') : j; } throw new SyntaxError('JSON.parse'); }; }

     通过一系列的替换操作,如果剩下的字符串只剩下 ]:,{}和空格,测试通过,接下来就可以用eval编译。

    如果parse方法的第二个参数存在,返回walk的调用结果,否则直接返回eval编译结果。

    //reviver的用法:
    // var jsontext = '{ "hiredate": "2008-01-01T12:00:00Z", "birthdate": "2008-12-25T12:00:00Z" }'; 
    // var dates = JSON.parse(jsontext, dateReviver); 
    // console.log(dates); 
     
    // function dateReviver(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; 
    // }; 
  • 相关阅读:
    CodeForces Gym 100500A A. Poetry Challenge DFS
    CDOJ 486 Good Morning 傻逼题
    CDOJ 483 Data Structure Problem DFS
    CDOJ 482 Charitable Exchange bfs
    CDOJ 481 Apparent Magnitude 水题
    Codeforces Gym 100637G G. #TheDress 暴力
    Gym 100637F F. The Pool for Lucky Ones 暴力
    Codeforces Gym 100637B B. Lunch 找规律
    Codeforces Gym 100637A A. Nano alarm-clocks 前缀和
    TC SRM 663 div2 B AABB 逆推
  • 原文地址:https://www.cnblogs.com/qianlegeqian/p/4166990.html
Copyright © 2011-2022 走看看