【问题标题】:Strange behaviour in JSON.stringify with replacer functionJSON.stringify 中带有替换函数的奇怪行为
【发布时间】:2014-01-28 20:41:24
【问题描述】:

考虑一下:

var object = {date: new Date()};

JSON.stringify(object, function(key, value) {
    console.log('---');
    console.log('key:', key);
    console.log('value:', value);
    console.log('value instanceof Date:', value instanceof Date);

    return value;
});

正如documentation 所说:

replacer 参数可以是函数或数组。作为一个函数,它有两个参数,键和值被字符串化。找到密钥的对象作为替换器的 this 参数提供。最初,它使用一个表示正在字符串化的对象的空键调用,然后为正在字符串化的对象或数组上的每个属性调用它。

...

如果您返回任何其他对象,则该对象会递归地字符串化为 JSON 字符串,并在每个属性上调用替换函数,除非该对象是一个函数,在这种情况下不会向 JSON 字符串添加任何内容。

但是如果你运行代码,你会得到这个:

---
key: 
value: { date: Fri Jan 10 2014 02:25:00 GMT+0100 (CET) }
value instanceof Date: false
---
key: date
value: 2014-01-10T01:25:00.262Z
value instanceof Date: false

这意味着,在调用替换函数之前,日期属性已被字符串化。这是正常行为还是我错过了什么?如何在不覆盖默认toJSON 方法的情况下影响Date 字符串化的格式?

谢谢!

编辑

根据回复和下一次研究,此时文档似乎还不清楚,toJSON 在替换函数之前被调用。根据 Pills 的回复,这个 sn-p 应该可以完成这项工作:

var object = {date: new Date };

JSON.stringify(object, function(key, value) {
    if (typeof(value) === 'object') {
        for (var k in value) {
            if (value[k] instanceof Date) {
                value[k] = value[k].getTime();
            }
        }
    }
    return value;
});

编辑#2

Xotic750 的解决方案比之前的好很多。

【问题讨论】:

  • 文档似乎有点不清楚,但似乎在为单个属性进行回调之前完成了字符串化。你可以试试这样的:jsfiddle.net/95eeS
  • 查看JSON2 的来源,任何toJSON 方法都会在替换器之前被调用。

标签: javascript json


【解决方案1】:

它很安静,但只是为了完成它。

根据this Q/A 和MDN JSON.stringify article,替换器是用找到密钥的对象的实例调用的,因此无需更改原型或执行其他技巧:

function log(what) {
   what = what || "";
   document.getElementById("out").innerText += what + "\n";
}

function replacer(key, value) {
   console.log(this);
   log("Key: '" + key + "' = '" + value + "'");
   log("this = " + this);
   log("this[key] = " + this[key]);
   log("this[key] instanceof Date = " + (this[key] instanceof Date));
   log("this instanceof Date = " + (this[key] instanceof Date));
   
   if (this[key] instanceof Date) {
      return "This was a date: " + this[key].getTime();
   }
   
   return value;
}

var obj = {
   d: new Date()
};

var result;
result = JSON.stringify(new Date(), replacer);
log();
log(result);
log();
result = JSON.stringify(obj, replacer);
log();
log(result);
<pre id="out"></pre>

【讨论】:

  • 仅供参考,您可以在 Stack Snippets 中使用 console.log,它会显示结果。它甚至会显示对象而不是[object Object]。
  • 我在小提琴中工作,所以我只是复制粘贴。但感谢您提供信息。
  • 这看起来确实比删除原型更高效,但是是什么让这个方法比自己迭代对象更好(问题中的编辑)?
  • 这是 100% 的正确答案。我很惊讶这没有更好的记录。
【解决方案2】:

也许您可以在将对象传递给 JSON 之前进行格式化,但也有可能:

JSON 在调用替换器之前使用对象toJSON 方法。

所以,在调用stringify 之前存储toJSON 方法,然后再恢复它。

var object = {
        date: new Date()
    },
    storeToJSON = Date.prototype.toJSON;

delete Date.prototype.toJSON;

JSON.stringify(object, function (key, value) {
    console.log('---');
    console.log('key:', key);
    console.log('value:', value);
    console.log('value instanceof Date:', value instanceof Date);

    return value;
});

Date.prototype.toJSON = storeToJSON;

开启jsFiddle

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-12
    • 1970-01-01
    • 2012-02-24
    • 2012-04-25
    • 1970-01-01
    • 2011-10-24
    相关资源
    最近更新 更多