Implementation of JSON.parse ()

1. JSON.parse()

JSON.parser () is a function in JSON format. It is used to convert the object data type to JSON data type.

2. Advance knowledge

2.1 Data types in JSON format

In the JSON format, the types of data that need to be processed can be divided into the following 6 categories. Note that the attribute types that need to be processed have the following 6 categories, which represent 6 cases of data processing; the
real data classification is not according to the following Yes, you need to pay attention here.

  1. String
  2. digital
  3. Boolean value
  4. null value
  5. symbol
  6. Strings containing escape characters (strings and strings containing escape characters are handled differently)

2.2 Handling of escaped characters

2.2 Determine whether the objects are equal

Implement a function yourself to judge whether two objects are equal, the implementation code is as follows:

// 判断两个对象是否相等的函数
const objectEquals = (a, b) => {
    // 如果 a, b相等,则返回 true,否则返回 false

    // Object.getOwnPropertyNames()方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组
    // 换句话来说 Object.getOwnPropertyNames()方法返回的是对象所有 key 组成的数组 list
    var aProps = Object.getOwnPropertyNames(a)
    var bProps = Object.getOwnPropertyNames(b)
    if (aProps.length != bProps.length) {
        return false
    }

    for (var i = 0; i < aProps.length; i++) {
        var propName = aProps[i]
        if (typeof a[propName] === 'object') {
            let judge = objectEquals(a[propName], b[propName])
            if (!judge) {
                return false
            }
        } else if (a[propName] !== b[propName]) {
            return false
        }
    }
    return true
}

2.3 Find matching strings

The matching string here is mainly the matching of brackets, understand the following code

// 返回对象 '{' 对应的 '}',返回数组 '[' 对应的 ']'
const getAimIndex = (string, index) => {
    let str = string
    // breakStr是结束判断字符
    let startStr = str[index]
    let breakStr = startStr === '{' ? '}' : ']'
    let judgeNum = 0
    /*
    判断逻辑:
        1. 遍历从 i = 1 开始
        2. if temp = '{' || '[', judgeNum++
        3. if temp = '}' || ']', judgeNum--
        4. if temp = '}' || ']' && judgeNum === 1, return i
     */
    for (let i = index, len = str.length; i < len; i++) {
        let temp = str[i]
        if (temp === startStr) {
            judgeNum++
        } else if (temp === breakStr && judgeNum !== 1) {
            judgeNum--
        } else if (temp === breakStr && judgeNum === 1) {
            return i
        }
    }
    // log('judgeNum: ', judgeNum)
}

let str = '{{{}}}'
console.log(getAimIndex(str, 0))

2.4 Basic recursive thinking

In this implementation process, the realization of a lot of content needs to be completed recursively, so it is better to have a basic understanding of recursion.

The understanding process may not be very strenuous, but if you implement it yourself, personally think that if you can determine whether Title2.2 is equal and implement the object independently, you can implement JSON.parse () yourself

3. Implementation process

3.1 Parsing JSON string into an array of tokens

In the production of the tokens array, intuitively, we will think that we only need to add the meaningful strings in the JSON to the tokens array, but there will be a problem with this:

For the following code

{
    "obj1": true,
    "obj2": "true"
}

In the above code, the obj1 and obj2 properties are essentially different, one is of type String and the other is of type Boolean, and the content types we read from JSON are all of type String; therefore in order to ensure perfect parsing of JSON data, we must The value type of JSON data stored in the tokens array

At the same time, because we must rely on the type of value when generating an object, the value itself generates the object, so we need to provide a method to return the value content

In summary, we use object-oriented thinking to solve this problem:

const log = console.log.bind(console)

const TYPE = {
    "[object Number]": 1,
    "[object String]": 2,
    "[object Null]": 3,
    "[object Boolean]": 4,
    "character": 5,
    "escapeCharater": 6
}

const includeEscapeCharacter = function(str) {
    let asciiEscape = [0, 39, 34, 92, 10, 13, 11, 9, 8, 12]
    for (let i = 0, len = str.length; i < len; i++) {
        let temp = str[i].charCodeAt(0)
        if (asciiEscape.indexOf(temp) !== -1) {
            return true
        }
    }
    return false
}

const dealEscape = (str) => {
    let escape = {
        b: `\b`,
        f: '\f',
        n: '\n',
        r: '\r',
        t: '\t',
        '\\': '\\',
        '\/': '\/',
        '\"': '\"',
        "\'": "\'"
    }
    let result = ''
    let string = str
    let i = 0
    let len = string.length
    // log(str)
    while (i < len) {
        let temp = string[i]
        if (temp === '\\') {
            let endIndex = i + 1
            result += escape[string[endIndex]]
            i = endIndex + 1
        } else {
            result += temp
            i++
        }
    }
    return result
}

const getType = function (value) {
    if (value === ':' || value === '{' || value === '}' || value === '[' || value === ']') {
        return 5
    }
    if (includeEscapeCharacter(value)) {
        return 6
    }
    let type = Object.prototype.toString.apply(value)
    return TYPE[type]
}

class JsonValue {
    constructor(value) {
        this.value = String(value)
        this.type = getType(value)
    }

    toString() {
        if (this.type === 1) {
            return Number(this.value)
        } else if (this.type === 2) {
            return String(this.value)
        } else if (this.type === 3) {
            return null
        } else if (this.type === 4) {
            return this.value === 'true'
        } else if (this.type === 5) {
            return String(this.value)
        } else if (this.type === 6) {
            return dealEscape(this.value)
        }
    }
}

const __main = () => {
    let a = new JsonValue('a')
    let b = new JsonValue(1)
    log(a)
    log(a.toString())
    log(b)
    log(b.toString())
}

__main()

All the data stored in the tokens array is JsonValue;

Next, traverse the JSON data to add content

3.2 Splicing the tokens array into Object objects

This process is to traverse the tokens array, according to the index of the symbol (:), tokens [index-1] is the key, tokens [index + 1] is the value; find the key-value pair, and then add it to the result; need to pay attention to This process needs to consider the nesting of Object and the nesting of Object in Array, here we need to use recursion to deal with

The core code of this process is as follows: According to different situations, deal with different content

// 获取key-value对的value值
const getTokensValue = (index, array) => {
    let judge = array[index].value
    if (judge === '{') {
        let nextIndex = getAimIndex(array, index)
        let sliceList = array.slice(index + 1, nextIndex)
        return parsedDict(sliceList)
    } else if (judge === '[') {
        let nextIndex = getAimIndex(array, index)
        let sliceList = array.slice(index + 1, nextIndex)
        return conversionObj(sliceList)
    } else {
        return array[index].toString()
    }
}

4. code

Code address: Implementation of JSON.parse ()

Guess you like

Origin www.cnblogs.com/oulae/p/12749375.html