I am trying to understand why JSON.stringify
shows a different output to the object I am expecting to see.
In my case, my object
has a property
of height
and width
So, if I were to do perform the following
const canvas = new fabric.Canvas("c");
console.log("canvas.width: " + canvas.width)
Then the output would be
canvas.width: 300
However, when I perform
console.log(JSON.stringify(canvas));
the output does not include the width.
In my real situation, I am using fabricjs.com
JSFiddle: https://jsfiddle.net/tdge2908/2/
<canvas id="c"></canvas>
<div id="result">
</div>
const canvas = new fabric.Canvas("c");
console.log("canvas.isRendering: " + canvas.width)
const result= document.getElementById("result");
result.innerText = JSON.stringify(canvas);
Likewise, I could add something to my canvas object, and it still won’t show when I stringify it.
EG
const canvas = new fabric.Canvas("c");
canvas.myMadeUpThing = "hello";
console.log("canvas.my made up thing: " + canvas.myMadeUpThing ); //this works
const result= document.getElementById("result");
result.innerText = JSON.stringify(canvas);
JSFiddle: https://jsfiddle.net/tdge2908/4/
Why does calling JSON.stringify
on this object seem to be doing something unexpected?
2
Answers
The behavior you’re observing is due to how JSON.stringify handles object properties in JavaScript. JSON.stringify only serializes the object’s own enumerable properties, which are the properties that are directly defined on the object itself and are enumerable.
In the case of Fabric.js objects, many properties (like width and height) are not directly enumerable properties of the canvas object. They are likely accessed through getters and setters or are inherited properties. Therefore, JSON.stringify will not include these properties in its output.
To demonstrate this, you can check the enumerable properties of an object using Object.keys:
To include non-enumerable properties in the output, you can use a custom replacer function with JSON.stringify. Here’s an example of how you might achieve this:
This replacer function will iterate over all properties (including non-enumerable and inherited properties) of each object it encounters and include them in the resulting JSON string.
However, be cautious with this approach, as it may include a lot of additional properties that you might not want in the JSON string, potentially leading to very large output. Adjust the logic within the replacer function to include only the properties you need.
Here is an updated version of your JSFiddle to include this behavior:
This should help you see all the properties, including those like width and your custom property myMadeUpThing.
The object returned by
new fabric.Canvas("c")
has atoJSON
method on its prototype chain. This method — when present — is called byJSON.stringify
, and overrides the default behaviour.Note that
width
is an own, enumerable property, so that is not the reason it wouldn’t be included in the JSON output.You could (temporarily) set
canvas.toJSON
toundefined
and then runJSON.stringify
, butcanvas
has circular references, so that meansJSON.stringify
will not be able to serialise it anymore.A solution could be to override
canvas.toJSON
so it returns an object with the properties of interest.For example: