recursive JSON.stringify implementation

后端 未结 6 1859
被撕碎了的回忆
被撕碎了的回忆 2021-02-04 21:25

I am trying to learn recursion in Javascript, so I figured I\'d rewrite the native JSON.stringify function using recursion as a challenge to myself. I almost got my

6条回答
  •  刺人心
    刺人心 (楼主)
    2021-02-04 21:57

    New answer to an old question

    There's some painfully bad answers here that fail under even the simplest examples. This answer aims to answer the question exhaustively and demonstrate how an approach like this scales even when handling a wide variety of data types and ...

    Corner cases

    This function does a simple case analysis on a non-null data's constructor property and encodes accordingly. It manages to cover a lot of corner cases that you're unlikely to consider, such as

    • JSON.stringify(undefined) returns undefined
    • JSON.stringify(null) returns 'null'
    • JSON.stringify(true) returns 'true'
    • JSON.stringify([1,2,undefined,4]) returns '[1,2,null,4]'
    • JSON.stringify({a: undefined, b: 2}) returns '{ "b": 2 }'
    • JSON.stringify({[undefined]: 1}) returns '{ "undefined": 1 }'
    • JSON.stringify({a: /foo/}) returns { "a": {} }

    So to verify that our stringifyJSON function actually works properly, I'm not going to test the output of it directly. Instead, I'm going to write a little test method that ensures the JSON.parse of our encoded JSON actually returns our original input value

    // we really only care that JSON.parse can work with our result
    // the output value should match the input value
    // if it doesn't, we did something wrong in our stringifier
    const test = data => {
      return console.log(JSON.parse(stringifyJSON(data)))
    }
    
    test([1,2,3])     // should return [1,2,3]
    test({a:[1,2,3]}) // should return {a:[1,2,3]}
    

    Disclaimer: it should be obvious that the code I'm about to share is not meant to be used as an actual replacement for JSON.stringify – there's countless corner cases we probably didn't address. Instead, this code is shared to provide a demonstration for how we could go about such a task. Additional corner cases could easily be added to this function.


    Runnable demo

    Without further ado, here is stringifyJSON in a runnable demo that verifies excellent compatibility for several common cases

    const stringifyJSON = data => {
      if (data === undefined)
        return undefined
      else if (data === null)
        return 'null'
      else if (data.constructor === String)
        return '"' + data.replace(/"/g, '\\"') + '"'
      else if (data.constructor === Number)
        return String(data)
      else if (data.constructor === Boolean)
        return data ? 'true' : 'false'
      else if (data.constructor === Array)
        return '[ ' + data.reduce((acc, v) => {
          if (v === undefined)
            return [...acc, 'null']
          else
            return [...acc, stringifyJSON(v)]
        }, []).join(', ') + ' ]'
      else if (data.constructor === Object)
        return '{ ' + Object.keys(data).reduce((acc, k) => {
          if (data[k] === undefined)
            return acc
          else
            return [...acc, stringifyJSON(k) + ':' + stringifyJSON(data[k])]
        }, []).join(', ') + ' }'
      else
        return '{}'
    }
    
    // round-trip test and log to console
    const test = data => {
      return console.log(JSON.parse(stringifyJSON(data)))
    }
    
    test(null)                               // null
    test('he said "hello"')                  // 'he said "hello"'
    test(5)                                  // 5
    test([1,2,true,false])                   // [ 1, 2, true, false ]
    test({a:1, b:2})                         // { a: 1, b: 2 }
    test([{a:1},{b:2},{c:3}])                // [ { a: 1 }, { b: 2 }, { c: 3 } ]
    test({a:[1,2,3], c:[4,5,6]})             // { a: [ 1, 2, 3 ], c: [ 4, 5, 6 ] }
    test({a:undefined, b:2})                 // { b: 2 }
    test({[undefined]: 1})                   // { undefined: 1 }
    test([[["test","mike",4,["jake"]],3,4]]) // [ [ [ 'test', 'mike', 4, [ 'jake' ] ], 3, 4 ] ]

提交回复
热议问题