这个问题是多部分的 -
(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或其他任何语言的下一个序列化格式的人,请考虑此问题。
IMO对于给定对象应该有两种状态。序列化状态和反序列化状态。在具有更强类型系统的软件语言中,这通常不是问题。但是使用JavaScript中的JSON,如果在同一个对象上调用两次JSON.parse,我们会遇到致命的异常。同样,如果我们在同一个对象上调用两次JSON.stringify,我们就会进入一个不可恢复的状态。就像我说的那样,应该只有两个状态和两个状态,简单的JS对象和序列化的JS对象。
答案 0 :(得分:3)
1)JSON.parse需要一个字符串,你正在为它提供一个Javascript对象。
2)与第一个类似的问题。您将字符串提供给需要对象的函数。
3)Stringfy实际上需要一个字符串,但是你正在为它提供一个String对象。因此,它应用相同的度量来转义引号和斜杠,就像第一个字符串一样。这样语言就可以理解引号,字符串中的其他特殊字符。
4)你可以为此编写自己的函数。
5)因为你试图做一个非法的转换。这与第一个和第二个问题有关。只要输入了正确的对象类型,您就可以根据需要多次调用它。唯一的问题是额外的斜杠,但它实际上是标准。
答案 1 :(得分:2)
我们将从您创作的噩梦开始: string 输入和整数输出。
IJSON.parse(IJSON.stringify("5")); //=> 5
内置的 JSON 功能不会让我们失败: string 输入和 string 输出。
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.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"
鲍勃的留言看起来不错。我们来看看爱丽丝的。
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
需要字符串类型。
现在你看到了光吗?
答案 2 :(得分:2)
我将尝试给你一个理由,为什么在没有问题的情况下,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文档而且它本应该不返回它?