Encountering a JavaScript toJSON custom method causing a StackOverflow error

Unique Scenario

Upon discovering this answer, a new idea struck me - creating an object from a JSON literal.

This led me to believe I could do the opposite using the handy JSON method: JSON.stringify(myObject).

Curious, I proceeded as follows:

function MyObject(id, value, desc)
{
  this.id = id;
  this.value = value;
  this.desc = desc;
  this.toJSON = function()
  {
    return JSON.stringify(this);
  }

}

However, upon running this code (demo), it threw a Maximum call stack size exceeded error.

After some searching, I came across two resources explaining this behavior:

It seems that .toJSON overrides the .stringify method, leading to a loop when called within itself.

Thought-provoking Questions

  1. (general) Why was the design choice made for toJSON? Is it a reserved or special keyword?
  2. (specific) To resolve the stack overflow issue, I opted to rename .toJSON to .display, which felt somewhat inelegant. Are there alternative solutions?

Answer №1

Seems like the issue is related to toJSON being semi-reserved: stringify checks if the object has a method called toJSON and then attempts to call it to stringify the result.


A possible workaround could be: (Although the reliability of this code is uncertain)

var obj = {
    value: 1,
    name: "John",
    toJSON: function() {
        var ret,
            fn = this.toJSON;

        delete this.toJSON;

        ret = JSON.stringify(this);

        this.toJSON = fn;

        return ret;
    }
}

Example:

obj.toJSON(); // "{\"value\":1,\"name\":\"John\"}"
obj.lastName = "Smith";
obj.toJSON(); // "{\"value\":1,\"name\":\"John\",\"lastName\":\"Smith\"}"

Alternatively, using a closure may provide a cleaner solution: (Which I believe is safe)

var obj = {
    value: 1,
    name: "John",
    toJSON: (function() {
        function fn() {
            var ret;
            delete this.toJSON;

            ret = JSON.stringify(this);

            this.toJSON = fn;

            return ret;
        }
        return fn;
    })()
}

After reading @filmor's comment, I considered another approach to address this issue. Although not elegant, it gets the job done.

By utilizing Function.caller, I can determine if fn is invoked using JSON.stringify

var obj = {
    value: 1,
    name: "John",
    toJSON: (function() {
        return function fn() {
            var ret;

            delete this.toJSON;

            ret = JSON.stringify(this);

            if ( fn.caller === JSON.stringify ) {
                ret = JSON.parse( ret );
            }

            this.toJSON = fn;

            return ret;
        }
    })()
}

Answer №2

Is the method toJSON considered reserved?

I'm uncertain of its reservation status, but one example is the native Date object utilizing toJSON to generate a formatted date string:

(new Date()).toJSON();           // -> "2019-05-22T09:30:42.123Z"
JSON.stringify({d: new Date()}); // -> {"d":"2019-05-22T09:30:42.123Z"}"

A simple workaround:

Create a custom stringify function that disregards any toJSON methods (it can be incorporated into the existing global JSON):

JSON.customStringify = function (obj) {

    var fn = obj.toJSON;
    obj.toJSON = undefined;
    var json = JSON.stringify(obj);
    obj.toJSON = fn;
    return json;
}

Now this can be easily applied to all objects:

function CustomObject(id, value, desc)
{
  this.id = id;
  this.value = value;
  this.desc = desc;
  this.toJSON = function()
  {
    return JSON.customStringify(this);
  }
}

To enhance simplicity further, include:

JSON.customStringifyMethod = function () {

    return JSON.customStringify(this);
}

Objects can now be structured as follows:

function CustomObject(id, value, desc)
{
  this.id = id;
  this.value = value;
  this.desc = desc;
  this.toJSON = JSON.customStringifyMethod;
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Managing websites on Android when the keyboard is displayed

I am currently facing an issue with my webpage on Android (Galaxy SIII). The problem occurs when visitors try to enter their email in the form at the bottom of the page. The keyboard becomes visible, causing the design to look messy. When using Chrome, the ...

What could be causing the error in Angular Universal Server Side Rendering after deployment on Firebase Hosting?

Currently immersed in Angular development utilizing third-party libraries such as Angular CLI/Angular Universal, following the guidelines laid out here. Also, integrating Firebase hosting and real-time database. The application works flawlessly on my local ...

Setting the maximum width for a JavaScript pop-up box

Below is the html code that creates a link reading "sacola de compras" <div> <script type="text/javascript" src="https://app.ecwid.com/script.js?4549118"></script> <script type="text/javascript"> xMinicart("style=","layout=Mini") ...

`Trigger a page reload when redirecting`

Currently, I am tackling some bug fixes on an older Zend Framework 1.10 project and encountering difficulties with redirection and page refresh. The issue: The task at hand is to make an AJAX call, verify if a person has insurance assigned, and prevent de ...

The JSON output is only displaying the final object in the array

Currently, I am working on creating a custom JSON feed for my WordPress page. The issue I am facing is that the loop seems to be overwriting every object, resulting in only the last object being printed as JSON. I have attempted moving the echo inside the ...

What is the meaning of "bootstrapping" as it relates to Angular 2?

I found a question that is similar to mine, but I think my case (with version 2) has enough differences to warrant a new discussion. I'm curious about the specific purpose of calling bootstrap() in an Angular 2 application. Can someone explain it to ...

Unable to add new Instance Properties in Vue.js within a Laravel project

I am attempting to develop a localization property similar to __('text') in Laravel blade template. I have set up a global window variable that contains all required data under the name window.i18n Below is my resourses/js/app.js file: require(& ...

The Jquery Ajax call is prompting the download of a JSON file instead of entering the success block

I have been facing an issue with uploading an excel file to a database in MVC5. The upload process is successful, after which the uploaded data should be displayed. I am trying to achieve both of these actions within a single action method. public ActionR ...

Steps to define a JavaScript mixin in VueJS

Currently, I am working on a Vue project with TypeScript and in need of using a mixin from a third-party library written in JavaScript. How can I create a .d.ts file to help TypeScript recognize the functions defined in the mixin? I have attempted the fol ...

Responsive design involves ensuring that web elements such as divs are properly aligned

I am currently working on aligning 2 divs in a specific way that is responsive. I would like the right div to stack on top of the left div when the screen width reaches a certain point, as opposed to them both taking up 50% of the container's width. ...

Filtering an RXJS BehaviorSubject: A step-by-step guide

Looking to apply filtering on data using a BehaviorSubject but encountering some issues: public accounts: BehaviorSubject<any> = new BehaviorSubject(this.list); this.accounts.pipe(filter((poiData: any) => { console.log(poiData) } ...

Unraveling the mystery of extracting special variables from HTML textarea input

How can I parse the input from a textarea using PHP or JS to replace special variables like {name} with an actual name instead of displaying {name} literally? I want users to be able to represent someone's name by entering {name} in their submission. ...

Determine whether a directive possesses a specific attribute

Here is my current code snippet: <my-directive></my-directive> I am trying to include a ternary operation within it like this: {{ $scope.my-option ? 'YES' : 'NO' }} Is it possible to achieve the desired result by adding ...

Sending JSON data from Flutter to a fresh Stateful Widget

After passing JSON data to a new stateful widget in Flutter, I encountered an issue where the widget was receiving null data despite seeing the data in the debug console. I have tried different methods of passing data types, but none seem to work. Can any ...

When it comes to the CSS `:visited` pseudo-class, I have

I'm having trouble changing the color of the anchor tag and blurring the image after visiting the link. Despite my CSS code, only the color is changing and the image remains unchanged. Here's my CSS code: <style> .image123{ paddin ...

Jenkins: Access a variable stored in a JSON file and incorporate it into subsequent actions

Encountered a problem with Jenkins. When making an HTTP request, I receive a JSON file structured like this: httpRequest authentication: 'b689fe3c-117e-4076-b10d-fe16ab14742f', httpMode: 'POST', outputFile: 'merge.json', resp ...

Locate an element within an array of strings to refine the contents of a flatlist

Currently, I have a FlatList that I am attempting to filter using multiple inputs from dropdown selectors. Here is the code snippet for my FlatList component: <FlatList style={styles.list} data={data.filter(filteredUsers)} ...

Exploring the Evolution of jsAjaxForm from jQuery Version 2.1.3 to Version 3.2.1

I'm in the process of upgrading to a higher version of jQuery (3.2.1) and encountering difficulties with updating the ajax file upload functionality using jsAjaxForm from jQuery v2.1.3. Is there a similar function that performs the same role as jaAjax ...

Flask - Refreshing Forms Dynamically

In an effort to enhance the responsiveness of my app, I am looking for a way to prevent the page from reloading every time a POST request is sent. My current setup includes a dynamically generated form with input fields designed like this: <div class=&q ...

The Javascript function call from the <img src="myFunction()"> is malfunctioning

I am looking to dynamically pass the URL of an image using a JavaScript function. <head> <script> function myFunction() { var str1 = "somepictureurl.png"; return str1; } </script> </head> <body> <img src="myFu ...