You can achieve a generic JSON.stringify()
that includes non-enumerables with code like below. But first, some notes:
This code has not been thoroughly tested for possible bugs or unexpected behavior; also, it turns functions into basic objects. Treat accordingly.
copyEnumerable()
is the function to pay attention to. It does not itself internally call JSON.stringify()
(you can do that yourself, with the output object) mainly because recursive calls to JSON.stringify()
(due to nested objects) will yield uglier, unwanted results.
I'm only checking for object
and function
types to be treated specially; I believe that these are the only types which need to be handled specially... Note that JS Arrays
([]
) fall into this category (objects), as well as classes (functions), and null
does not. Since null
is of type object
, I included the !!
check.
The stopRecursiveCopy
Set
is just to make sure it's not doing infinite recursion.
I'm using a trick with the 2 extra parameters to JSON.stringify()
calls to make it output something formatted prettier, for easy reading.
The code is in an easy format to try out and tweak in the console:
{
o = {};
d = {};
Object.defineProperties(o, {
a: {
value: 5,
enumerable: false
},
b: {
value: "test",
enumerable: false
},
c: {
value: {},
enumerable: false
}
});
Object.defineProperty(o.c, "d", {
value: 7,
enumerable: false
});
//The code to use (after careful consideration!).
function isObject(testMe) {
return ((typeof(testMe) === "object" && !!testMe) ||
typeof(testMe) === "function");
}
let stopRecursiveCopy = new Set();
function copyEnumerable(obj) {
if (!isObject(obj)) {
return obj;
}
let enumerableCopy = {};
for (let key of Object.getOwnPropertyNames(obj)) {
if (isObject(obj[key])) {
if (!stopRecursiveCopy.has(obj[key])) {
stopRecursiveCopy.add(obj[key]);
enumerableCopy[key] = copyEnumerable(obj[key]);
stopRecursiveCopy.delete(obj[key]);
}
} else {
enumerableCopy[key] = obj[key];
}
}
return enumerableCopy;
}
console.log(JSON.stringify(copyEnumerable(o), null, " "));
Object.defineProperty(copyEnumerable, "test", {
value: 10,
enumerable: false
});
console.log(JSON.stringify(copyEnumerable(copyEnumerable), null, " "));
Object.defineProperty(o, "f", {
value: copyEnumerable,
enumerable: false
});
console.log(JSON.stringify(copyEnumerable(o), null, " "));
}
which outputs:
//o
{
"a": 5,
"b": "test",
"c": {
"d": 7
}
}
//copyEnumerable itself
{
"test": 10,
"prototype": {
"constructor": {
"test": 10,
"length": 1,
"name": "copyEnumerable"
}
},
"length": 1,
"name": "copyEnumerable"
}
//o again, but with `f: copyEnumerable` added
{
"a": 5,
"b": "test",
"c": {
"d": 7
},
"f": {
"test": 10,
"prototype": {},
"length": 1,
"name": "copyEnumerable"
}
}
Pertinent links: