JSON.parse方法是如何工作的?

JSON.parse方法是如何工作的?

最后修改时间:7 months ago

JSON.parse 方法一直以为一直就这么用了,大致也知道它对于字符串格式比较严格,即便有时候可以通过编译器解释器,但是却若非标准 json 格式就无法转成 object。这次也因为后端一个奇怪的返回,我决定好好搞懂它。

# 代码验证

首先,依据是老规矩,代码验证,因为后端返回的三种格式分别如下:

  • '["sdalkjald"]'
  • '{"attachment":"请上传开发自测报告"}'
  • "服务器错误"

于是,为了能兼容 3 者,我作了如下方法进行处理,

    var a = '["sdalkjald"]',
        b = '{"attachment":"请上传开发自测报告"}',
        c = "服务器错误",
        p = (e)=>{
            try {
                let obj = JSON.parse(e);
                if (Array.isArray(obj)) {
                    return obj[0];
                }
                if (typeof obj == "object") {
                    console.log(`"${e}"为正常 json 对象`);
                    return obj;
                }
                return e;
            } catch (err) {
                console.log(`"${e}"无法被解析`);
                return e;
            }
        };
    console.log(typeof h(a));
    console.log(typeof h(b));
    console.log(typeof h(c));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

执行结果:

"["sdalkjald"]"解析为数组
string
"{"attachment":"请上传开发自测报告"}"解析为对象
object
"服务器错误"无法被解析
string
1
2
3
4
5
6

一切似乎都在预期内,但是我总感觉,事情没这么简单。

本着折腾本腾的使命感,我打算继续塞些奇奇怪怪的参数进去跑一跑,为了方便测试,我对上述代码进行了改造

var testArr = [
    '["hello"]',
    ["hello"],
    '{"attachment":"请上传开发自测报告"}',
    '{"attachment":"请上传开发自测报告",}',
    "服务器错误",
    "true",
    false,
    123,
    "123",
    {},
    "{}"
  ],
  p = (e) => {
    try {
      let obj = JSON.parse(e);
      if (Array.isArray(obj)) {
        console.log(`${e} => 数组`)
        return;
      }
      switch (typeof obj) {
        case "object":
        case "number":
        case "boolean":
          console.log(`${e} => ${typeof e}`)
          return;
      }
    } catch (err) {
      // 对象或者字符串将无法通过 JSON.parse
      console.log(`${e} => 无法被解析`)
      return;
    }
  };
testArr.forEach((e) => p(e));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34

为了方便对应,我直接给出了对照

参数 元数据类型 返回结果 是否能被解析
'["hello"]' string object(array)
["hello"] object(array) -
'{"attachment":"请上传开发自测报告",}' string -
'{"attachment":"请上传开发自测报告"}' string object
"服务器错误" string -
"true" string boolean
false boolean boolean
123 number number
"123" string number
{} object -
"{}" string object

# 结论

对象、以及非特殊字符串无法被 JSON.parse() 解析到;

这让我想到了 eval() ,两者对于绝大多数的解析几乎一致;

将测试方法中的 JSON.parse(e) 更为 eval("("+e+")") 后,可以达到对照表

参数 元数据类型 返回结果 是否能被解析 是否与 JSON.parse() 结果一致
'["hello"]' string object(array)
["hello"] object(array) -
'{"attachment":"请上传开发自测报告",}' string object
'{"attachment":"请上传开发自测报告"}' string object
"服务器错误" string -
"true" string boolean
false boolean boolean
123 number number
"123" string number
{} object -
"{}" string object

可以看到,两者确实存在极其相似的特性。

区别主要在于,字符串除了标准 json 串、 numberboolean 以外,非标准 json 串,亦可以解析。

那么是否 eval()JSON.parse() 更佳呢?

答案是不能!

var G = '{ "title" : "some title" , "text" : window.location.href="https://www.baidu.com" }';
1

执行上述语句,可以看到,页面甚至跳转到了百度

所以,当数据来源无法可信时,使用 eval 并不安全。

so...

# 参考

- 全文完 -

留下一条留言?
默认颜色

主题颜色

标准颜色

更多颜色...