使用Javascript的递归方法

时间:2017-03-09 05:58:11

标签: javascript arrays json recursion

我正在尝试复制json stringify方法,而是使用递归。我已经能够传递很多测试用例但是当涉及到嵌套数组时,我似乎遇到了问题。如果数组中有任何空数组('[]'),我得到类似[,7,9]而不是[[],7,9]的东西。如果我传入的话:

stringifyJSON([[["test","mike",4,["jake"]],3,4]])
"[[test,mike,4,jake,3,4]]"

我认为我已经接近了这个工作,但我可能不得不重新开始。你们有什么想法我可以改变什么来使这个工作嵌套的例子?这是我现在的代码:

var testarray = [9,[[],2,3]] //should return '[9,[[],2,3]]'
var count = 0
var stringifyJSON = function(obj,stack) {
	var typecheck = typeof obj;
	var resarray = stack;
	if(resarray == null){	//does resarray exist? Is this the first time through?
		var resarray = [];
	}
	if(typeof obj === "string"){	//Is obj a string?
		return '"' + String(obj) + '"';
	}

	if((Array.isArray(obj)) && (obj.length > 0)){  //If not a string, is it an object?
		for(var i = 0; i<obj.length;i++){
			if(Array.isArray(obj[i])){
				var arraytemp = []
				stringifyJSON(arraytemp.push(obj[i]),resarray)   // this is probably incorrect, this is how i handle a nested array situation
			}
			if(typeof obj[i] === 'number'){		//if the number is inside of the array, don't quote it
				resarray.push(obj[i]);
			}
			else if(typecheck === 'object' && Array.isArray(obj[0])){
				resarray.push('[' + obj[i] + ']');
			}
			else{
				resarray.push('"' + obj[i] + '"');
			}
			
			obj.shift()		//delete the first object in the array and get ready to recurse to get to the second object.
			stringifyJSON(obj,resarray);  //remember the new array when recursing by passing it into the next recursive instance
		}
	}

	if(obj !== null && typeof obj === 'object'){	//is obj an object?
		for(var key in obj){
			stringifyJSON(resarray.push(key + '"' + ':' + obj[key]),resarray)
		}
		

	}
	if(typeof obj === "number" || obj == null || obj === true || obj === false){	//special cases and if it's a number
		return '' + obj + ''
	}
	if(typecheck === 'object'){	//a special case where you have an empty array that needs to be quoted.
		return '['+resarray+']'
	}
	return '' + resarray.join('') + '';

	

};

//JSON values cannot be a function, a date, or undefined

2 个答案:

答案 0 :(得分:2)

  

你们对于我可能能够改变什么以使其适用于嵌套示例有什么想法吗?

当然,但它会废弃你的整个功能,所以我希望你不要介意。我将提供一个点清单,说明为什么这种方法是必不可少的,而你的基本上有缺陷从一开始 :(

转角案件

此函数对非空数据的constructor属性进行简单的案例分析,并进行相应编码。它设法涵盖了您不太可能考虑的许多极端案例,例如

  • JSON.stringify(undefined)返回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({a: /foo/})返回{ "a": {} }

因此,为了验证我们的stringifyJSON函数实际上是否正常工作,我不会直接测试它的输出。相反,我将编写一个小test方法,以确保我们编码的JSON的JSON.parse实际返回我们的原始输入值

// 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]}
  

免责声明:很明显,我要分享的代码并不打算用作JSON.stringify的实际替代 - 我们可能无法解决的无数角落案例。相反,这个代码是共享的,以提供我们如何进行此类任务的演示。可以轻松地将其他角落案例添加到此功能中。

Runnable演示

不用多说,这里有一个可运行的演示中的stringifyJSON,可以验证几种常见情况的出色兼容性

&#13;
&#13;
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([[["test","mike",4,["jake"]],3,4]]) // [ [ [ 'test', 'mike', 4, [ 'jake' ] ], 3, 4 ] ]
&#13;
&#13;
&#13;

&#34;为什么这样更好?&#34;

  • 这不仅适用于数组类型 - 我们可以字符串化字符串,数字,数组,对象,数组,对象数组,包含字符串数组的对象,甚至nullundefined s,等等 - 你明白了
  • 我们的stringifyJSON对象的每个案例就像一个小程序,告诉我们如何编码每种类型(例如StringNumberArray,{{1等等)
  • 没有检查Object类型检查 - 在我们检查typeofundefined个案后,我们知道我们可以尝试阅读null属性。
  • 没有手动循环,我们必须在心理上跟踪计数器变量,如何/何时递增它们
  • 使用constructorif&&或检查||等内容时没有复杂的!条件
  • 没有使用强调我们大脑的x > y.lengthobj[0]
  • 没有关于数组/对象为空的假设 - 没有必须检查obj[i]属性
  • 没有其他突变 - 这意味着我们不必考虑一些主回报值length或在resarray次呼叫发生后的状态该计划的各个阶段

自定义对象

push允许我们在自定义对象上设置JSON.stringify属性,这样当我们对它们进行字符串化时,我们就会得到我们想要的结果。

&#13;
&#13;
toJSON
&#13;
&#13;
&#13;

我们可以轻松地将这种功能添加到上面的代码中 - 更改粗体

const Foo = x => ({
  toJSON: () => ({ type: 'Foo', value: x })
})

console.log(JSON.stringify(Foo(5)))
// {"type":"Foo","value":5}

答案 1 :(得分:0)

因此,在使用您的代码后,我发现如果您更换:

git commit --amend

with:

resarray.push('[' + obj[i] + ']');它适用于数组并且仍然满足您的递归过程。

此外,我发现有一些怪癖通过像resarray.push(stringifyJSON(obj[i]))这样的对象运行它,并发现通过改变对象的字符串化来:

{ hello: 5, arr: testarray, arr2: [1, 2,3, "hello"], num: 789, str: '4444', str2: "67494" };

更像是:

stringifyJSON(resarray.push(key + '"' + ':' + obj[key]),resarray)

它应该更多地锻炼你想要的东西。这真的很酷,我玩得很开心!