zoukankan      html  css  js  c++  java
  • 利用原生 js 模拟出 JSON.parse 和 JSON.stringify

    最近利用原生 javascript 模仿出原生的 JSON.parse 和 JSON.stringify 的效果

    (function (win) {
      const MOCK_JSON = {
        // 记录结构体的数量(结构体是指字符串格式的[]和{})
        structure_len: 0,
        // 记录结构体的结构对象
        map_data: {},
        structure_key: '$',
        init() {
          this.structure_len = 0
          this.map_data = {}
          this.structure_key = '$'
        },
        parse(str) {
          this.init()
          // this.inspectionFormat()        
          let reg = /\/g
          if (reg.test(str)) {
            if (str[0] == '"') {
              str = str.slice(1, str.length - 1)
            }
            return str.replace(reg, '')
          }
          str = str.replace(/[ /g, '[')
          str = str.replace(/s,/g, ',')
          str = str.replace(/,s/g, ',')
          str = str.replace(/s:/g, ':')
          str = str.replace(/:s/g, ':')
          // 处理结构体 key
          let $arr = str.match(/$+/g)
          let $len = $arr[0].length
          for (let i = 1; i < $arr.length; i++) {
            if ($len < $arr[i].length) {
              $len = $arr[i].length
            }
          }
          let $key = this.structure_key
          for (let i = 0; i < $len; i++) {
            this.structure_key += $key
          }
          return this.handleData(str, 0)
        },
        inspectionFormat(obj) {
          let regObject = /{"?.+[^"]:.+}|{[^"].+"?:.+}|{[^"]|{":|{".*"}|{".*":.{0}}|{".*"[^:].{0}}|,}| "/g
          let regArray = /[,.*|.*,]/g
          if (regObject.test(obj)) {
            throw new Error('{} 数组格式有误')
          }
          if (regArray.test(obj)) {
            throw new Error('[] 数组格式有误')
          }
        },
        changeData(data) {
          --this.structure_len
          if (this.callType(data) == 'array') {
            let array = []
            let len = data.length
            for (let i = 0; i < len; i++) {
              let elem = data[i]
              if (this.callType(elem) == 'string' && elem.indexOf(this.structure_key) > -1) {
                array.push(this.changeData(this.map_data[elem]))
              } else {
                array.push(this.handleValue(elem))
              }
            }
            if (!this.structure_len) {
              this.init()
            }
            return array
          } else if (this.callType(data) == 'object') {
            let object = {}
            for (let attr in data) {
              let value = data[attr]
              if (this.callType(value) == 'string' && value.indexOf(this.structure_key) > -1) {
                object[attr] = this.changeData(this.map_data[value])
              } else {
                object[attr] = value
              }
            }
            if (!this.structure_len) {
              this.init()
            }
            return object
          }
        },
        handleData(obj, idx) {
          let left_brace = obj.lastIndexOf('{'),
            right_brace = obj.slice(left_brace).indexOf('}'),
            left_bracket = obj.lastIndexOf('['),
            right_bracket = obj.slice(left_bracket).indexOf(']')
          if (left_brace == -1 && left_bracket == -1) {
            return this.changeData(this.map_data[this.structure_key + (this.structure_len - 1)])
          }
          // 最小结构体为 {}
          if (left_brace > left_bracket) {
            this.map_data[`${this.structure_key}${idx}`] = this.handleObject(obj.slice(left_brace, left_brace + right_brace + 1))
              ++this.structure_len
            let left_surplus = obj.slice(0, left_brace)
            let right_surplus = obj.slice(left_brace + right_brace + 1)
            return this.handleData(`${left_surplus}${this.structure_key}${idx}${right_surplus}`, ++idx)
          } else if (left_brace < left_bracket) {
            // 最小结构体为 []
            this.map_data[`${this.structure_key}${idx}`] = this.handleArray(obj.slice(left_bracket, left_bracket + right_bracket + 1))
              ++this.structure_len
            let left_surplus = obj.slice(0, left_bracket)
            let right_surplus = obj.slice(left_bracket + right_bracket + 1)
            return this.handleData(`${left_surplus}${this.structure_key}${idx}${right_surplus}`, ++idx)
          } else {
            // 最外层为 {}
            if (obj[0] == '{') {
              this.map_data[`${this.structure_key}${idx}`] = this.handleObject(obj)
                ++this.structure_len
            }
            // 最外层为 []
            if (obj[0] == '[') {
              this.map_data[`${this.structure_key}${idx}`] = this.handleArray(obj)
                ++this.structure_len
            }
          }
        },
        // 对象字符串格式化为对象
        handleObject(obj) {
          let newObj = {}
          // 空对象
          if (obj.length == 2) {
            return newObj
          }
          // 检查对象格式
          let regObject = /{"?.+[^"]:.+}|{[^"].+"?:.+}|{[^"]|{":|{".*"[^:]}|{".*":.{0}}|{".*"[^:].{0}}|,}/g
          if (regObject.test(obj)) {
            throw new Error(obj + ' 对象结构有误')
          }
          // 去除对象左右{}符号
          obj = obj.slice(1, obj.length - 1)
          // 先根据逗号分割
          let obj_arr = obj.split(',')
          obj_arr.forEach((elem) => {
            // 再根据冒号分割 key 和 value
            let obj_data = elem.split(':')
            for (let o = 0; o < obj_data.length; o++) {
              let key = this.handleKey(obj_data[o])
              let value = this.handleValue(obj_data[++o])
              newObj[key] = value
            }
          })
          return newObj
        },
        // 数组字符串格式化为数组
        handleArray(arr) {
          let newArr = []
          // 空数组
          if (arr.length == 2) {
            return newArr
          }
          // 检查数组格式
          let reg = /[,.*|.*,]/g
          if (reg.test(arr)) {
            throw new Error(arr + ' 数组格式有误')
          }
          return arr.slice(1, arr.length - 1).split(',').map((elem) => this.handleValue(elem))
        },
        handleKey(key) {
          return key.replace(/"/g, '')
        },
        handleValue(value) {
          // 空字符串
          if (value.length == 0) {
            return value
          }
          // 存储字符串长度
          let str_len = 0
          if (this.callType(value) == 'string') {
            value = value.replace(/"/g, '')
            str_len = value.length
          }
          // 字符串中无数字
          if (isNaN(parseFloat(value))) {
            return value
          } else {
            // 字符串中有数字(字符串数字化后是否与原先字符串一致)
            let temp = '' + parseFloat(value)
            // 不一致(例如:parseFloat('123abc'))
            if (temp.length != str_len) {
              return value
            } else {
              // 一致(例如:parseFloat('123'))
              return parseFloat(value)
            }
          }
        },
        // 分辨类型
        callType(obj) {
          let map = {
            '[object Object]': 'object',
            '[object Array]': 'array',
            '[object Number]': 'number',
            '[object Null]': 'null',
            '[object Boolean]': 'boolean',
            '[object Symbol]': 'symbol',
            '[object Undefined]': 'undefined',
            '[object Function]': 'function',
            '[object RegExp]': 'regexp',
            '[object String]': 'string',
            '[object Date]': 'date',
            '[object Math]': 'math',
          }
          return map[Object.prototype.toString.call(obj)]
        },
        // json对象字符串化
        stringify(obj) {
          switch (this.callType(obj)) {
            case 'object':
              let listObj = []
              for (let attr in obj) {
                listObj.push(`"${attr}":${this.stringify(obj[attr])}`)
              }
              return `{${listObj.join(',')}}`
            case 'array':
              let listArr = []
              obj.forEach((elem) => {
                listArr.push(this.stringify(elem))
              })
              return `[${listArr.join(',')}]`
            case 'number':
            case 'null':
            case 'boolean':
              return String(obj)
            case 'symbol':
            case 'undefined':
            case 'function':
            case 'regExp':
              return undefined
            case 'string':
              return `"${obj.replace(/"/g, '\"')}"`
            case 'date':
              return `"${obj.toISOString()}"`
            case 'math':
              return `{}`
          }
        }
      }
      win.MOCK_JSON = MOCK_JSON
    })(window)

    代码中也有简单的注释

  • 相关阅读:
    CSP 命令行选项(201403-3)
    ElasticSearch7.10的查询数据-简单查询
    ElasticSearch 种映射参数详解-理论学习02
    Elasticsearch7.10 -理论学习01
    ElasticSearch7.10索引
    ElasticSearch7.10的分词器
    ElasticSearch-7.10安装-2
    ElasticSearch第一天
    Idea的注释配置
    深圳第一站被骗消费3960元
  • 原文地址:https://www.cnblogs.com/webBlog-gqs/p/14170545.html
Copyright © 2011-2022 走看看