JSON.parse和JSON.stringify不是幂等的,这是不好的
这个问题是多方面的 -
(1a)JSON是JavaScript的基础,那么为什么没有JSON类型? JSON类型将是一个格式为JSON的字符串。 它会被标记为解析/字符串化,直到数据被更改。 只要数据发生变化,它就不会被标记为JSON,并且需要重新分析/重新串联。
(1b)在一些软件系统中,不可能(意外地)试图通过网络发送一个普通的JS对象而不是一个序列化的JS对象? 为什么不试图避免呢?
(1c)为什么我们不能直接在一个JavaScript对象上调用JSON.parse
,而不是先将其字符串化呢?
var json = { //JS object in properJSON format
"baz":{
"1":1,
"2":true,
"3":{}
}
};
var json0 = JSON.parse(json); //will throw a parse error...bad...it should not throw an error if json var is actually proper JSON.
所以我们别无选择,只能这样做:
var json0= JSON.parse(JSON.stringify(json));
但是,有一些不一致之处,例如:
JSON.parse(true); //works
JSON.parse(null); //works
JSON.parse({}); //throws error
(2)如果我们在同一个对象上继续调用JSON.parse
,最终会抛出一个错误。 例如:
var json = { //same object as above
"baz":{
"1":1,
"2":true,
"3":{}
}
};
var json1 = JSON.parse(JSON.stringify(json));
var json2 = JSON.parse(json1); //throws an error...why
(3)为什么JSON.stringify
无限地在输入中添加越来越多的斜杠? 它不仅难以读取调试结果,而且实际上会使您处于危险状态,因为一个JSON.parse调用不会返回一个普通的JS对象,您必须多次调用JSON.parse才能找回纯JS的对象。 这很糟糕,意味着在给定的JS对象上多次调用JSON.stringify是非常危险的。
var json = {
"baz":{
"1":1,
"2":true,
"3":{}
}
};
var json2 = JSON.stringify(json);
console.log(json2);
var json3 = JSON.stringify(json2);
console.log(json3);
var json4 = JSON.stringify(json3);
console.log(json4);
var json5 = JSON.stringify(json4);
console.log(json5);
(4)函数的名称是什么,我们应该能够反复调用而不改变结果(IMO如何处理JSON.parse
和JSON.stringify
)? 这个最好的术语似乎是“幂等的”,你可以在评论中看到。
(5)考虑到JSON是一种可用于网络对象的序列化格式,在某些情况下,您不能调用JSON.parse
或JSON.stringify
两次或甚至一次,而不会引发一些问题,这似乎完全疯狂。 为什么会这样?
如果您正在为Java,JavaScript或任何语言发明下一个序列化格式,请考虑此问题。
国际海事组织应该有两个国家为一个给定的对象。 一个序列化状态和一个反序列化状态。 在具有更强类型系统的软件语言中,这通常不是问题。 但在JavaScript中使用JSON时,如果在同一对象上调用JSON.parse两次,则会遇到致命异常。 同样,如果我们在同一个对象上调用两次JSON.stringify,我们可能会陷入不可恢复的状态。 就像我说的应该只有两个状态和两个状态,普通的JS对象和序列化的JS对象。
1)JSON.parse需要一个字符串,你给它一个Javascript对象。
2)与第一个类似的问题。 您将一个字符串提供给需要对象的函数。
3)Stringfy实际上期望一个字符串,但是你给它一个String对象。 因此,它将采用与第一个字符串相同的措施来避免引号和斜线。 因此,该语言可以理解引号,字符串内的其他特殊字符。
4)你可以为此编写自己的函数。
5)因为您正在尝试进行非法转换。 这与第一个和第二个问题有关。 只要提供正确的对象类型,就可以多次调用它。 唯一的问题是额外的斜线,但它实际上是标准。
我们将从您创建的这个噩梦开始:字符串输入和整数输出。
IJSON.parse(IJSON.stringify("5")); //=> 5
内置的JSON函数不会以这种方式让我们失败:字符串输入和字符串输出。
JSON.parse(JSON.stringify("5")); //=> "5"
JSON必须保留您的原始数据类型
把JSON.stringify
成一个函数,把数据包装在一个盒子里,把JSON.parse
作为把它从盒子里拿出来的函数。
考虑以下:
var a = JSON.stringify;
var b = JSON.parse;
var data = "whatever";
b(a(data)) === data; // true
b(b(a(a(data)))) === data; // true
b(b(b(a(a(a(data)))))) === data; // true
也就是说,如果我们将数据放在3个框中,我们必须从3个框中取出。 对?
如果我将数据放在2个框中并从1中删除,那么我还没有保存我的数据,我持有一个包含我的数据的框。 对?
b(a(a(data))) === data; // false
对我来说似乎理智......
JSON.parse
解开你的数据。 如果它没有装箱,它不能解开它。 JSON.parse
需要一个字符串输入,并且给它一个JavaScript对象字面值
对JSON.parse
的第一个有效调用将返回一个对象。 在这个对象输出上再次调用JSON.parse
将导致与#1相同的失败
反复调用JSON.stringify
会多次“ JSON.stringify
”我们的数据。 所以当然你必须重复调用JSON.parse
然后才能从每个“盒子”中获取数据
幂等
不,这是完全理智的。 你不能三重印戳。
你永远不会犯这样的错误,对吧?
var json = IJSON.stringify("hi");
IJSON.parse(json);
//=> "hi"
好吧,那是幂等的,但那又如何
var json = IJSON.stringify("5");
IJSON.parse(json);
//=> 5
UH OH! 我们每次给它一个字符串,但第二个例子返回一个整数。 输入数据类型已丢失!
JSON函数会在这里失败吗?
var json = JSON.stringify("hi");
JSON.parse(json);
//=> "hi"
都好。 那么"5"
呢?
var json = JSON.stringify("5");
JSON.parse(json));
//=> "5"
耶,类型已被预先保存! JSON
作品, IJSON
不。
也许一个更真实的例子:
好的,所以你有很多开发人员在忙着应用程序。 它会对您的基础数据的类型做出鲁莽的假设。 假设这是一个聊天应用程序,它可以在消息从点到点的过程中进行多次转换。
一路上你会有:
IJSON.stringify
IJSON.parse
IJSON.parse
是因为谁在乎? 它是幂等的,对吗? String.prototype.toUpperCase
- 因为这是一个格式选择 让我们看看这些消息
bob: 'hi'
// 1) '"hi"', 2) <network>, 3) "hi", 4) "hi", 5) "HI"
Bob的消息看起来很好。 我们来看看Alice的。
alice: '5'
// 1) '5'
// 2) <network>
// 3) 5
// 4) 5
// 5) Uncaught TypeError: message.toUpperCase is not a function
不好了! 服务器刚刚崩溃。 你会注意到它甚至不是IJSON.parse
的重复调用,在这里失败了。 即使你曾经叫过它,它也会失败。
似乎你从一开始就注定要死去......诅咒鲁莽的开发者和他们粗心的数据处理!
如果Alice使用任何发生的也是有效的JSON的输入,它将会失败
alice: '{"lol":"pwnd"}'
// 1) '{"lol":"pwnd"}'
// 2) <network>
// 3) {lol:"pwnd"}
// 4) {lol:"pwnd"}
// 5) Uncaught TypeError: message.toUpperCase is not a function
好吧,不公平的例子也许吧? 你在想,“我不是那么鲁莽,我不会在这样的用户输入上调用IJSON.stringify
或IJSON.parse
!” 没关系。 您从根本上破坏了JSON,因为原始类型不能再提取。
如果我使用IJSON
一个字符串,然后取消它,谁知道我会回来? 当然不是你,当然不是开发者使用你的鲁莽功能。
这是不可能告诉的!
你处在一个全新的痛苦世界中,因为你从一开始就对你的数据类型一直不小心。 你的类型很重要,所以请小心处理它们。
JSON.stringify
需要一个对象类型,而JSON.parse
需要一个字符串类型 。
现在你看到光了吗?
我会试着给你一个理由,说明为什么JSON.parse不能在没有问题的情况下在同一个数据上被多次调用。
你可能不知道它,但一个JSON文件不一定是一个对象。
这是一个有效的JSON文档:
"some text"
让我们将这个文档的表示存储在一个javascript变量中:
var JSONDocumentAsString = '"some text"';
并努力工作:
var JSONdocument = JSON.parse(JSONDocumentAsString);
JSONdocument === 'some text';
这会导致错误,因为这个字符串不是JSON文档的表示
JSON.parse(JSONdocument);
// SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
在这种情况下怎么可能有JSON.parse
猜测JSONdocument
(作为一个字符串)是一个JSON文档,它应该已经回到它不变?
上一篇: JSON.parse and JSON.stringify are not idempotent and that is bad
下一篇: How to JSON.stringify and JSON.parse without getting an empty object?