问题描述
我正在尝试学习Javascript中的递归,所以我想我会使用递归作为对自己的挑战来重写本机 JSON.stringify
函数。我几乎得到了我的代码:
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 code to work:
var my_stringify = function(obj){
value = obj[ Object.keys(obj)[0] ];
index = Object.keys(obj)[0];
delete obj[ Object.keys(obj)[0] ];
// The value is just a simple string, not a nested object
if (typeof value === 'string'){
if (Object.keys(obj).length !== 0){
// Continue recursion ..
return '"' + index + '":"' + value + '",' + my_stringify(obj);
}
// This would be the base case with a string at the end. Stop recursion.
return '"' + index + '":"' + value + '"}';
}
// The value is actually a nested object
else{
if (Object.keys(obj).length !== 0){
// Continue recursion ..
return '"' + index + '":{' + my_stringify(value) + ',' + my_stringify(obj);
}
// This is the base case with a nested object at the end. Stringify it and end recursion.
return '"' + index + '":{' + my_stringify(value) + '}';
}
}
除了第一个<$ c $我的答案中缺少c> {,我无法弄清楚如何解决这个问题。
Except for the fact that the first {
in my answer is missing, and I can't figure out how to fix this bug.
例如。 my_stringify({foo:'bar'})
返回foo:bar}
而不是 {foo:bar}
。
另外,我知道我完全摧毁了原始物体,有没有办法发送到递归减少版本的原始对象而不删除任何东西(类似 obj.slice(1)
)?
Also, I'm aware I'm completely destroying the original object, is there any way to send over to recursion a reduced version of the original object without deleting anything (something like obj.slice(1)
)?
我们将非常感谢任何建议!
Any advice will be greatly appreciated !
推荐答案
旧问题的新答案
这里有一些非常糟糕的答案,即使是最简单的例子也是如此。这个答案的目的是详尽地回答这个问题,并演示如何处理各种数据类型和...这样的方法可以扩展...
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 ...
角点案例
此函数对非空数据的构造函数
属性进行简单的案例分析,并进行相应的编码。它设法涵盖了你不太可能考虑的许多极端情况,例如
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
-
JSON.stringify(null)
返回'null'
-
JSON.stringify(true)
返回'true'
-
JSON.stringify([1,2,undefined,4])
返回'[1,2,null,4]'
-
JSON .stringify({a:undefined,b:2})
返回'{b:2}'
-
JSON.stringify({[undefined]:1})
返回'{undefined:1}'
-
JSON.stringify({a:/ foo /})
返回{a: {}}
JSON.stringify(undefined)
returnsundefined
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": {} }
所以验证我们的 stringifyJSON
函数实际上工作正常,我不打算直接测试它的输出。相反,我将编写一个小的测试
方法,以确保我们编码的JSON的 JSON.parse
实际返回我们的原始输入值
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]}
Runnable demo
不用多说,这里有一个可运行的演示中的 stringifyJSON
,可以验证几个常见的兼容性case
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 ] ]
这篇关于递归JSON.stringify实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!