2017-03-09 45 views
1

我試圖複製json stringify方法,而是使用遞歸。我已經能夠通過大量的測試用例,但是當涉及到嵌套數組時,我似乎遇到了問題。如果數組中有任何空數組('[]'),我會得到類似[,7,9]而不是[[],7,9]的東西。另外,如果我傳遞:使用Javascript的遞歸方法

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) { 
 
\t var typecheck = typeof obj; 
 
\t var resarray = stack; 
 
\t if(resarray == null){ \t //does resarray exist? Is this the first time through? 
 
\t \t var resarray = []; 
 
\t } 
 
\t if(typeof obj === "string"){ \t //Is obj a string? 
 
\t \t return '"' + String(obj) + '"'; 
 
\t } 
 

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

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

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

 
\t 
 

 
}; 
 

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

+0

我沒有通過代碼了,但woudlnt」你的變化 -

const Foo = x => ({ toJSON:() => ({ type: 'Foo', value: x }) }) console.log(JSON.stringify(Foo(5))) // {"type":"Foo","value":5}

我們可以很容易這樣的功能添加到我們的代碼以上調用遞歸函數時需要返回?例如'return stringifyJSON(...)' – derp

+0

這是一個有趣的問題嘗試和解決,但要確保它只是爲了鍛鍊而不是實際使用的東西 - 我在下面的答案中提供了許多細節。如果您有任何問題,我很樂意提供幫助。 – naomik

回答

0

所以你的代碼玩弄後,我發現,如果要更換:

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)

到更多的東西,如:

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

它應該更多地鍛鍊你的想法。這真的很酷,但我玩得很開心!

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的演示

事不宜遲,下面是在驗證了幾種常見的情況

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

極好的兼容性可運行演示

「那麼,爲什麼這更好?」

  • 這個工程的不僅僅是數組類型 - 我們可以字符串化字符串,數字,數組,對象,數字數組,對象數組,包含字符串數組,即使null S和undefined的S對象,並等等 - 你的想法
  • 我們stringifyJSON對象的每一種情況下就像一個小程序,它告訴我們究竟是如何每種類型的編碼(如StringNumberArrayObject等)
  • 沒有疲憊不堪了typeof類型檢查 - 在我們檢查undefinednull個案後,我們知道我們可以嘗試閱讀constructor屬性。
  • 沒有手動循環,我們必須在精神上保持跟蹤計數器變量,如何/時使用&&||!,或檢查之類的東西x > y.length
  • 沒有用的obj[0]來增加他們
  • 沒有複雜的if條件或obj[i],強調我們的大腦出
  • 沒有關於數組/對象是空的假設 - 和無需檢查length財產
  • 個沒有其他突變對於這個問題 - 這意味着我們不必去想一些主要的返回值resarray或者什麼狀態時,它是在後push電話在不同階段的程序發生

自定義對象

JSON.stringify允許我們在我們的自定義對象上設置一個toJSON屬性,這樣當我們對它們進行字符串化時,我們將得到我們想要的結果。在大膽

const stringifyJSON = data => { 
    if (data === undefined) 
    return undefined 
    else if (data === null) 
    return 'null' 
    else if (data.toJSON instanceof Function) return stringifyJSON(data.toJSON()) 
    ... 
    else 
    return '{}' 
} 

test({toJSON:() => ({a:1, b:2})}) // { a: 1, b: 2 }