Javascript toJSON自定义方法上的Stackoverflow错误

Javascript toJSON自定义方法上的Stackoverflow错误,javascript,json,oop,design-patterns,Javascript,Json,Oop,Design Patterns,场景 阅读之后,我意识到我可以从JSON文本开始创建对象 因此,我猜想我可以使用这个有用的JSON方法来做相反的事情: JSON.stringify(myObject) 因此,我做了如下工作: function MyObject(id, value, desc) { this.id = id; this.value = value; this.desc = desc; this.toJSON = function() { return JSON.stringify(t

场景

阅读之后,我意识到我可以从JSON文本开始创建对象

因此,我猜想我可以使用这个有用的JSON方法来做相反的事情:
JSON.stringify(myObject)

因此,我做了如下工作:

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

}
但是当我运行这个东西()时,出现了一个
超过最大调用堆栈大小的错误

在谷歌搜索了一下之后,我发现了两个可以解释这种行为的参考资料:

  • MDN的方法
  • 这篇文章在JSON.org上发表
如果我答对了,
.toJSON
将覆盖
.stringify
。因此,如果第一个调用第二个,将生成一个循环

问题

  • (概述)为什么选择这种设计
    toJSON
    是一种保留的特殊关键字吗
  • (具体)我解决了stackoverflow错误,将
    .toJSON
    名称改为
    .display
    。不那么优雅。还有别的解决办法吗

  • 认为这是因为
    toJSON
    是半保留的:
    stringify
    将检查对象,看看它是否有一个名为
    toJSON
    的方法,然后尝试调用它来字符串化结果


    解决方法可以是:(不确定此代码的可靠性)

    用法:

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

    也许使用clousure更漂亮一点:(然后我想我可以说它是安全的)


    所以在读了@filmor的评论后,我想到了另一种处理方法。不是很漂亮,但很管用

    使用我可以检测是否使用
    JSON.stringify
    调用了
    fn

    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;
            }
        })()
    }
    

    问题1,
    toJSON
    是否保留?

    我不确定它是否保留,但例如,原生日期对象使用toJSON创建字符串化日期表示:

    (new Date()).toJSON();           // -> "2012-10-20T01:58:21.427Z"
    JSON.stringify({d: new Date()}); // -> {"d":"2012-10-20T01:58:21.427Z"}"
    
    问题2,一个简单的解决方案:

    创建忽略toJSON方法的自定义stringify函数(您可以将其添加到现有的全局
    JSON
    ):

    现在,它很容易在所有对象中使用:

    function MyObject(id, value, desc)
    {
      this.id = id;
      this.value = value;
      this.desc = desc;
      this.toJSON = function()
      {
        return JSON.customStringify(this);
      }
    }
    
    为使其更加简单,请另外添加:

    JSON.customStringifyMethod = function () {
    
        return JSON.customStringify(this);
    }
    
    现在,您的对象可能看起来像:

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

    +1用于使用stackoverflow关键字。不,开玩笑,这是一个好问题。@ADC记得接受你的开放式问题。如果没有什么特别的,为什么要使用自定义的
    toJSON
    方法呢?发现这一点的时间与你差不多(在课程中崩溃Firefox之后;)。一条注释:如果这样做,就会破坏正常的
    JSON.stringify(obj)
    ,因为它会将对象解释为字符串,并转义和添加上下文“查斯。”或者我遇到了同样的问题。但是我想我发现了一个使用
    fn.caller
    的解决方案很有趣,但是仅仅使用
    toJSON
    intead of
    display
    :)就有很多东西。请注意,
    函数.调用者
    页面中有一条
    非标准
    备注。无论如何,这是一个优雅的解决方案。
    function MyObject(id, value, desc)
    {
      this.id = id;
      this.value = value;
      this.desc = desc;
      this.toJSON = function()
      {
        return JSON.customStringify(this);
      }
    }
    
    JSON.customStringifyMethod = function () {
    
        return JSON.customStringify(this);
    }
    
    function MyObject(id, value, desc)
    {
      this.id = id;
      this.value = value;
      this.desc = desc;
      this.toJSON = JSON.customStringifyMethod;
    }