Search code examples
javascriptjsonfabricjsstringify

JSON.stringify omits properties from object


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?


Solution

  • The object returned by new fabric.Canvas("c") has a toJSON method on its prototype chain. This method -- when present -- is called by JSON.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 to undefined and then run JSON.stringify, but canvas has circular references, so that means JSON.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:

    // Define a custum toJSON method for canvas elements:
    fabric.Canvas.prototype.toJSON = function() {
        const { width, height } = this;
        return { width, height };
    };
    
    const canvas = new fabric.Canvas("c");
    console.log(JSON.stringify(canvas));
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.1/fabric.min.js"></script>