I'm trying to stringfy an object with my custom function, I just do it for practice purposes. But the function doesn't return what I want.
Here is the whole function and the object I pass into.
const data = { hello: "world", is: true, nested: { count: 5 } };
const stringify = (obj, symbol, numRepeat, stringifiedObj) => {
const keys = Object.keys(obj);
const values = Object.values(obj);
// console.log("stringified object when functino runs", stringifiedObj);
// console.log("ALL KEYS", keys);
// console.log("ALL VALUES", values);
keys.forEach((key, index) => {
// console.log(typeof obj[key]);
if (typeof values[index] !== "object") {
console.log(values[index]);
// console.log(`{${key}: ${values[index]}}`);
stringifiedObj = `${key}: ${values[index]}\n`;
console.log("strinbgify inside if".toLocaleUpperCase(), stringifiedObj);
} else {
console.log("this is Object", obj[key]);
stringify(obj[key], symbol, values, stringifiedObj);
}
});
return `{${stringifiedObj}}`;
};
console.log("FUNCTION RETURN", stringify(data, "|-", 2, ""));
You can ignore symbol and numrepeat parameters since I will use them later.
so the expected result is
hello: world
is: true
nested:{
count: 5
}
but it returns;
hello: world
is: true
where am I doing wrong?
CodePudding user response:
This should be a fixed version. I added some comments in the code.
Basically with recursion you usually need to return
a value that will be grabbed in the nested iteration.
Array.ForEach does no return anything, just executes code of each item. Array.map instead, returns the result.
const data = { hello: "world", is: true, nested: { count: 5 } };
const stringify = (obj, symbol, numRepeat, stringifiedObj) => {
const keys = Object.keys(obj);
const values = Object.values(obj);
// Here you need to RETURN something, so array.map maps an array into something else and you can return a value
return keys.map((key, index) => {
if (typeof values[index] !== "object") {
// so return here the .map iteration
return stringifiedObj `${key}: ${values[index]}\n`; // You really need that \n at the end?
} else {
// else, return your other string
return stringify(obj[key], symbol, values, stringifiedObj);
}
});
// as we did -return keys.map- this one below is no longer needed
//return stringifiedObj;
};
console.log("FUNCTION RETURN", stringify(data, "|-", 2, ""));
CodePudding user response:
You might like this simple type analysis technique using switch
on t?.constructor
. Each case performs only what is necessary for each type's "shape" and recursively call stringify
on the type's child elements. By adding a default depth = 1
parameter, we are able to format the output using properly indented lines =
function stringify (t, depth = 1) {
switch (t?.constructor) {
case String:
return `"${t.replace(/"/g, '\\"')}"`
case Object:
return `{${linebreak(depth)}${
Object
.entries(t)
.map(([k,v]) => `${k}: ${stringify(v, depth 1)}`)
.join(`,${linebreak(depth)}`)
}${linebreak(depth - 1)}}`
case Array:
return `[${linebreak(depth)}${
t
.map(v => stringify(v, depth 1))
.join(`,\n${" ".repeat(depth)}`)
}${linebreak(depth - 1)}]`
default:
return String(t)
}
}
function linebreak (depth, s = " ") {
return `\n${s.repeat(depth)}`
}
const data =
{ hello: "world", is: true, nested: { count: 5, any: null, with: [ "array", undefined, { object: NaN } ] } }
console.log(stringify(data))
{
hello: "world",
is: true,
nested: {
count: 5,
any: null,
with: [
"array",
undefined,
{
object: NaN
}
]
}
}