V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
3dwelcome
V2EX  ›  前端开发

JSON 的 Keyname 到底要不要加双引号?

  •  
  •   3dwelcome · 2022-03-30 11:04:38 +08:00 · 5271 次点击
    这是一个创建于 729 天前的主题,其中的信息可能已经有所发展或是发生改变。
    浏览器里用 eval()解析一个 json 对象,keyname 是可以不带双引号的,比如{a:123}是合法的。

    然后同样是浏览器,用 JSON.parse()去解析一个 json 对象,就必须加双引号。否则直接报错!

    规范就不能统一一下嘛,一声叹息。
    49 条回复    2022-03-31 10:29:22 +08:00
    dcalsky
        1
    dcalsky  
       2022-03-30 11:05:57 +08:00   ❤️ 5
    你是把 js object 和 JSON 弄混了吧?

    定义: https://www.json.org/json-en.html
    3dwelcome
        2
    3dwelcome  
    OP
       2022-03-30 11:08:43 +08:00
    @dcalsky 今天碰到一个后端数据,返回的是没有引号的 keyname JSON 。

    我可以用 eval 来顺利解析,但总觉得很别扭。
    westoy
        3
    westoy  
       2022-03-30 11:11:46 +08:00   ❤️ 1
    一开始 gmail 大量使用 xhr, ajax 开始火了后,js object 替代 xml 成为数据标准后的一段时间确实有过很小一段时间的 eval parse 潮

    于是就出现了大量的类似这样的 eval("{};console.log('helloworld') || { x: 1}")构造攻击案例

    然后才出现了 json

    最后现代浏览器才慢慢开始支持 JSON.stringify 和 JSON.parse......
    nitmali
        4
    nitmali  
       2022-03-30 11:13:09 +08:00
    json 就是字符串,解析就是 js 对象
    tyx1703
        5
    tyx1703  
       2022-03-30 11:18:12 +08:00 via iPhone
    要加。
    eval 是当成代码执行的,key 不加引号在 js 语法层面是正常语句。
    westoy
        6
    westoy  
       2022-03-30 11:20:00 +08:00   ❤️ 1
    @3dwelcome

    让上游改吧, 正经的 json dump 库都是加双引号的, 没引号的估计是自己字符窜拼接出来的, 过滤不好可能埋雷的
    icyalala
        7
    icyalala  
       2022-03-30 11:20:40 +08:00
    你不加引号,叫后端和客户端这些没有浏览器环境的地方怎么解析嘛,引入个 JSON5 解析器?
    lovedebug
        8
    lovedebug  
       2022-03-30 11:21:24 +08:00
    JSON 有 RFC 规范的,通用版本是需要双引号的

    https://datatracker.ietf.org/doc/html/rfc8259
    3dwelcome
        9
    3dwelcome  
    OP
       2022-03-30 11:26:04 +08:00
    @icyalala 理论上客户端用的 JSON 解析器,也能支持一下非引号的 keyname 吧。
    shintendo
        10
    shintendo  
       2022-03-30 11:27:32 +08:00
    什么叫用 eval 解析,eval 是用来执行 js 代码的,只不过“碰巧”可以实现解析 json 的效果。
    能用 eval 顺利执行说明是合法的 js ,不说明是合法的 json ,json 规范写的明明白白,key 必须带双引号。
    shintendo
        11
    shintendo  
       2022-03-30 11:32:24 +08:00
    @3dwelcome 不符合规范,为啥要支持。你上面还说“规范就不能统一一下嘛”,现在又要求支持野生语法
    3dwelcome
        12
    3dwelcome  
    OP
       2022-03-30 11:38:17 +08:00
    @shintendo 汗,怎么就成了野生语法。正常手写 js 对象,大家都是不加引号的。

    我网上也搜了一下,强制引号是也有一定历史原因的,比如一些 js 语法关键词,早期解析时候就很容易失败,加个引号可以万无一失。

    既然 json 标榜着人类可读性最高,那么就应该向更友好的书写,更友好的阅读发展。没有引号,显然更符合人类阅读,而不是机器阅读。
    icyalala
        13
    icyalala  
       2022-03-30 11:46:53 +08:00
    @3dwelcome key 带引号是 JSON 规范,各种语言内置的 JSON 解析器和流行三方库基本都是按规范来的,尤其是一些为性能优化的库,比如 simdjson 。
    “方便人类来写”的规范,那就是 yaml 或者 json5 了。
    3dwelcome
        14
    3dwelcome  
    OP
       2022-03-30 11:54:13 +08:00
    @icyalala
    原来还有 JSON5.parse()这个替代函数,发帖前还不知道,涨姿势了。

    同时还支持了注释和单引号,果然够人性化,赞。
    zhaol
        15
    zhaol  
       2022-03-30 11:58:15 +08:00
    eval 是解析 js 代码的,eval 的参数是 string 类型,但是它里面的规范是符合 js 规范的(也就是对象的 key 不用带双引号,只不过前后加了个双引号包裹起来这段 js 语句),所以正常解析。JSON.parse 的参数也是 stirng ,但是它里面的规范是要符合 JSON 的规范的(也就是对象的 key 要带双引号),这是两个不同 api ,干嘛要统一?
    shintendo
        16
    shintendo  
       2022-03-30 12:44:46 +08:00   ❤️ 1
    @3dwelcome 汗,先分清楚 js 对象和 json 吧
    3dwelcome
        17
    3dwelcome  
    OP
       2022-03-30 12:46:27 +08:00


    看着这张 google 的 jsonnet 图片,仿佛领悟到了什么。

    首先,key 加双引号,肯定是反人类的。

    然而,JSON 作为计算机交换格式,为了最大限度的避免解析错误,引号又是不可避免的。

    于是,JS object 和 JSON 的关系,就变成了手写 JS object => 通过编译器变转译一次 => 变成机器可识别的 JSON 。
    shintendo
        18
    shintendo  
       2022-03-30 12:53:35 +08:00   ❤️ 2
    @3dwelcome 不存在编译……JSON 是一个独立的数据交换格式,它的灵感来源于 JS 的对象语法,这是它们仅有的关联。
    另外,JS 并不是任何时候都可以不写引号,而是某些 key 可以不写引号,某些 key 必须写引号,而了解 DC 的人都知道他对“做一件事只有一种方式”的偏执,所以在设计 JSON 的时候,既然不能统一不加引号,那就只能统一必须加引号。
    shintendo
        19
    shintendo  
       2022-03-30 12:59:21 +08:00   ❤️ 5
    可以去搜一下 The JSON Saga 这个演讲,里面 DC 详细解释了 JSON 的设计过程。
    他还提到一个趣事:JSON 的 License 里规定不能用来作恶,但是“作恶”是一个模糊的概念,所以 IBM 的法务写邮件问他,他就特别授权“IBM 可以用 JSON 来作恶”
    wdssmq
        20
    wdssmq  
       2022-03-30 13:09:07 +08:00
    @3dwelcome #12 人类可读性最高是 yml 谢谢。。
    wdssmq
        21
    wdssmq  
       2022-03-30 13:11:48 +08:00
    @shintendo #18 2333 ,,有趣的灵魂,,
    yolee599
        22
    yolee599  
       2022-03-30 13:15:43 +08:00 via Android
    JSON5 的 key 可以不用双引号
    jifengg
        23
    jifengg  
       2022-03-30 13:20:29 +08:00   ❤️ 1
    {
    "my name is":"jifengg"
    }

    想想这个 json 的 key 不加引号怎么写?
    dcsuibian
        24
    dcsuibian  
       2022-03-30 13:24:33 +08:00   ❤️ 1
    OP 和那个后端都应该去补下 JSON 知识了。
    1 、JSON 是来自于 JavaScript ,但是作为一种数据交换格式,严格了很多。
    2 、C 语言中,双引号代表字符串,单引号代表字符,对其它语言影响很大。js 、python 这种高级语言没有 char 这种单字符类型的,单引号和双引号的效果才差不多。js object 的 keyname 本身也就是字符串,不带引号那是简写,像{"function":"sum"}这种时候就不合适了。所以 JSON 规范规定强制加双引号是个很正确的决定。
    3 、后端数据,keyname 不带双引号?你们后端难道是拼接字符串给返回值的?拉出来打一顿
    4 、JSON.stringify()和 JSON.parse()都不了解
    有点超出我的想象了。。。
    Symo
        25
    Symo  
       2022-03-30 13:25:43 +08:00
    @wdssmq 人类阅读友好的应该是 TOML, YAML 的缩进在比较多之后很容易让人迷惑, 比如 k8s 的配置文件.
    wdssmq
        26
    wdssmq  
       2022-03-30 13:55:54 +08:00
    @Symo #24 好吧。。忘记这个了,想了想自己接触到的只有 git 的配置文件用了这种格式,,能自己选的话综合来说还是 yaml ,

    data = [ ["delta", "phi"], [3.14] ]
    temp_targets = { cpu = 79.5, case = 72.0 }

    视觉上个人感觉还是缩进更舒服。。- -
    3dwelcome
        27
    3dwelcome  
    OP
       2022-03-30 14:04:25 +08:00
    @dcsuibian 没那么多玄学,我只是用错函数了。把 JSON.parse()改成 JSON5.parse(),一切就都没问题了。

    JSON.parse()这函数毕竟年代久远,不能苛求太多。
    Puteulanus
        28
    Puteulanus  
       2022-03-30 14:04:27 +08:00
    用 eval 解析是真的牛逼。。
    DOLLOR
        29
    DOLLOR  
       2022-03-30 14:17:48 +08:00
    考虑要兼容更多的平台环境,最好还是要加。
    dcsuibian
        30
    dcsuibian  
       2022-03-30 14:45:35 +08:00
    @3dwelcome JSON5 不是 JSON 的新版本,没有得到官方的支持。实质上是另一个格式。JSON.parse()是浏览器自带的,打开控制台就能直接用,而 JSON5.parse()是第三方类库啊。而 JSON.parse()解析 JSON 没问题,那这个函数就是没问题的呀,也无所谓老不老。

    JSON5 作为 JSON 的超集,你用 JSON5.parse()把普通 JSON 转成 JavaScript 值没问题,但除此各方面就感觉挺别扭。因为实际上你是用了一个 XML 和 JSON 之外的特殊传输格式。MIME 类型也应该是`application/json5`。

    对应的 JSON5.stringify()的结果很可能无法被正常 JSON 解析器解析,在访问公共 API 的时候会出问题。如果你退化到使用 JSON.strinify(),又有什么理由不使用对应的 JSON.parse()呢
    iyaozhen
        31
    iyaozhen  
       2022-03-30 15:12:21 +08:00
    你就不能看看官方文档嘛?
    https://www.json.org/json-en.html
    3dwelcome
        32
    3dwelcome  
    OP
       2022-03-30 15:12:51 +08:00
    @dcsuibian 前端 JSX 代码大多都是转译的,用个第三方库来扩展 JS 或者 JSON 能力,是很普遍的事情。

    我一直觉得 tailwind css 最大的成功之处,就是语法没那么死板。用缩写 mx-5 来替代 margin-left 和 margin-right ,能少打很多代码,让程序可读性提高,变得清晰整洁。

    我最好连 html/xml 都能把引号给去掉,比如<button id=great_button onclick=alert(很好很强大)>显示按钮</button>
    3dwelcome
        33
    3dwelcome  
    OP
       2022-03-30 15:18:38 +08:00
    @iyaozhen 前端技术日新月异,json.org 上规范是 200x 年设立的,看 10 几年前的文档,显然没有足够的参考价值。

    有扩展新的规范,比如 google 的 jsonnet ,都是可以直接写无引号的。

    说说嘛前端需要不断创新,结果还是要拿十几年的老古董文件来压人。
    marcong95
        34
    marcong95  
       2022-03-30 15:29:05 +08:00   ❤️ 1
    @3dwelcome #32 想要简化 html 的话,pug 了解一下。

    我觉得你认为不加引号也应该是 JSON ,目测是看到 JSON 全称是 JavaScript Object Notation ,然而事实上 JSON 似乎已经成为了一个专有名词,只是因为源于 JS ,才叫的 JSON 。JavaScript Object Notation 跟 JavaScript Object 的区别就如同 Java 与 JavaScript 的区别一样大(优良传统了属于是
    icyalala
        35
    icyalala  
       2022-03-30 15:40:58 +08:00
    @3dwelcome JSON 标准体现在它能脱离 JS ,在所有地方都能作为 "数据交换" 使用。
    很多语言内置或流行三方库都支持 JSON 到原生 Object 的映射,各个数据库也都支持 JSON 导入导出或者 JSON 查询和 Patch ,甚至现在很多文件格式都直接基于 JSON 来定义。所有这些地方都是遵守那个 JSON 的标准。如果不遵守标准,那就不叫 JSON 了,这与创新无关。

    另外,JSON 标准也在一直更新,最新的标准是 2017 年的 RFC 8259 ,但没有破坏标准兼容性。
    3dwelcome
        36
    3dwelcome  
    OP
       2022-03-30 15:59:11 +08:00
    @icyalala 我个人觉得由于历史负担太重,JSON 标准官方就算想更新,也没办法更新。

    有那么多的老的 json 解析库,是不可能所有都更新的。
    shintendo
        37
    shintendo  
       2022-03-30 16:02:59 +08:00   ❤️ 14
    @3dwelcome
    恰恰相反,JSON 不更新版本是最正确的决定,作为一个数据交换格式,你今天拿到前端发来的请求不需要问他这是 JSON 2.6 还是 JSON 5.8 还是 JSON X 写的,都要谢谢 DC 的这个决定。
    你在主贴说着“规范就不能统一一下嘛,一声叹息”,别人告诉你 JSON 规范一直都是明确统一的,你又开始要创新要扩展要日新月异,全保定的理都让你占了。
    至于什么 JSX tailwind ,属于是越说槽点越多了,建议及时止损。
    Nooooobycat
        38
    Nooooobycat  
       2022-03-30 16:10:53 +08:00
    先是分不清[]和{},再然后是 OP 提到的后端疑似是拼接字符串返回 json 。。。现在程序员的水平可以这么低了吗
    keepeye
        39
    keepeye  
       2022-03-30 16:11:21 +08:00
    你调用一下 JSON.stringfy() 观察一下不就知道了吗?你猜一下,不带引号的"json"能不能被其他语言解析
    dcsuibian
        40
    dcsuibian  
       2022-03-30 16:17:49 +08:00
    @3dwelcome
    我的意思是,这东西扩展了,那它就不是正宗 JSON 了,更准确地说,就不是 JSON 了。
    tsconfig.json 用.json 作后缀,但能写注释和逗号,不是正宗的 JSON 。
    就像 jsx 能用.js 后缀,但已经不是正宗的 js 了。

    而相比于 jsx 这种,我认为使用 JSON 时更应该遵守标准,因为它作为一种独立于编程语言的格式。不是某个项目(tsconfig.json)、某个语言(js)特有的。JSON 标准的确定性是不可少的一个优点。大家只要明白是 JSON 就能处理,没那么多麻烦事,甚至不用说版本。

    而且 JSON 其实是非常优秀、先进的格式,现在还是相当好用的。新的格式没有比它好多少,没有什么替换的必要。
    主要问题就是有些人喜欢把它当配置文件用。(这点应该让 yaml 、toml 来说话)
    3dwelcome
        41
    3dwelcome  
    OP
       2022-03-30 16:18:24 +08:00
    @shintendo "至于什么 JSX tailwind ,属于是越说槽点越多了,建议及时止损。"

    我从头到尾的逻辑很清晰啊,就一条:科技以人为本,计算机能处理的双引号,就尽量避免人为去加。

    计算机写个兼容函数写法不难,难的是人写的代码里,有太多是为了去兼容计算机的。

    你说 tailwind 用 mx 替代 margin-left 和 margin-right 不是挺好的嘛,转译后计算机能理解 mx 含义。人写的代码越少,可维护性就越高。明明是个双赢的局面。
    shintendo
        42
    shintendo  
       2022-03-30 19:03:25 +08:00
    @3dwelcome "计算机能处理的双引号,就尽量避免人为去加"
    可是除了作为配置文件,我想不出需要人为加引号的场景,你不会真的像他们说的那样,后端拼接字符串吧
    Trim21
        43
    Trim21  
       2022-03-30 19:17:50 +08:00   ❤️ 1
    JSON 是个数据交换格式。所以 JSON 的规范都是为了数据交换而设置设置的。你搞的太零活了才不以人为本。

    你要的以人为本的那个是 JavaScript 的语法,键加不加括号都随意,甚至能像 `const obj = { user }` 一样直接把变量名和变量值作为键值对。js 对象就是你说的 “tailwind 里的 mx”,JSON 就是 css 里的“margin-left 和 margin-right ”
    oneisall8955
        44
    oneisall8955  
       2022-03-30 19:48:11 +08:00
    @3dwelcome #17

    https://imgur.com/a/mdP9q19

    出现这种情况就比较懊恼
    fan123199
        45
    fan123199  
       2022-03-30 20:38:18 +08:00
    我觉得 OP 对双引号有天然的反感在。其实一些规范老旧了,但他依然是规范。 你可以和自己的后端约定大家都用 json5 规范,或者 key 用数字等等,都可以,达到了美化代码的目的。但是这个就不是大家所公认的 JSON 了。 想要变规范,那就要去参与 rfc 规范修改。
    agagega
        46
    agagega  
       2022-03-30 20:46:04 +08:00
    Key 里有不合法字符怎么办?比如 - " :?那不还是得加上引号吗。那按照楼主「统一」的逻辑,不如都加上双引号?

    另外有大量的语言(即使是动态语言)是会严格区分键值对 a["b"] 和对象属性 a.b 的,JSON 的 Object 在其他语言看来就是个键值对,加双引号才符合直觉
    Mystery0
        47
    Mystery0  
       2022-03-31 01:30:52 +08:00 via Android
    op 遇到的后端,不会也是用 js 写的吧😂
    3dwelcome
        48
    3dwelcome  
    OP
       2022-03-31 01:40:04 +08:00 via Android
    @Mystery0 后端 API 返回的数据,是严格意义上的 JSON ,有引号,这没问题。
    但是在返回结果里,某个字符串里包着的,是 js object 对象,没引号。
    反正 eval 又不是不能用。
    dawniii
        49
    dawniii  
       2022-03-31 10:29:22 +08:00
    楼主难道是受到 jsonp 的影响。

    好多年前,好像应对跨域的情况有用 jsonp ,直接拿 js 代码执行。。。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5539 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 36ms · UTC 09:04 · PVG 17:04 · LAX 02:04 · JFK 05:04
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.