JSON 使用指南,以及配置文件解决方案

71,924 阅读9分钟

JSON(JavaScript Object Notation)是一种轻量级的 数据交换格式,易于人类读写,也易于机器解析和生成。

JSON 采用完全独立于语言的文本格式,类似于 XML,但比 XML 更加简洁优雅,常被用做 配置文件

JSON 基本语法规范

  1. JSON 文件的扩展名是 .json
  2. JSON 文本的 MIME 类型是 application/json
  3. JSON 是一个键值对(key/value)的集合,所有数据都保存在一个 JSON 对象中,该对象以左括号({)开始,以右括号(})结束,每个 key 后跟一个冒号(:),key 与 value 之间使用逗号(,)分隔。
    • 键(key)的数据类型是字符串,必须包裹在双引号中(忘了给 Key 加双引号或者是把双引号写成单引号是常见错误)。
    • 值(value)可以是这些类型:String、Number、Boolean、Object、Array、null。
{
  "description": "这是一个 JSON 对象",
  "sites": [
    { "name": "Apple", "url": "www.apple.com" },
    { "name": "Google", "url": "www.google.com" },
    { "name": "Facebook", "url": "www.facebook.com" }
  ]
}

需要注意的是:JSON 文件中无法使用注释,试图添加注释将会引发报错。但是可以通过变通的方法添加注释,如:

{
  "description": "项目配置文件",
  "version": "1.0.0",
  "author": "Tom"
}

{
  "======== common ========": "通用模块",
  "common": {
    "key1": "value1",
    "key2": "value2"
  },
  "========= user =========": "用户模块",
  "user": {
    "key1": "value1",
    "key2": "value2"
  }
}

JavaScript 对 JSON 的支持

JSON 语法是 JavaScript 语法的子集,当在 JavaScript 中使用 JSON 时,JSON 是其内置的功能。JSON 对象包含两个方法:用于解析 JSON 的 parse() 方法,以及将对象转换为 JSON 字符串的 stringify() 方法。除了这两个方法外,JSON 这个对象本身并没有其他作用,也不能被调用或者作为构造函数调用。

JSON 在 JavaScript 中的引用十分广泛,例如:从 Web 服务器上获取 JSON 数据,然后将该 JSON 数据转换为 JavaScript 对象进行使用。

兼容性:IE8 以下的浏览器不支持,对于较老的浏览器,可使用 JSON2 github.com/douglascroc…

JSON.parse()

JSON.parse() 函数用于 JSON 解析,即将一个 JSON 字符串转换成一个 JavaScript 对象。

语法:JSON.parse(text[, reviver])

  • text:必需,一个有效的 JSON 字符串。
  • reviver:可选,一个结果转换函数,将为对象的每个成员调用此函数。
const jsonStr = '{ "name": "Tom", "birthday": "2020-01-01" }'

const jsObj1 = JSON.parse(jsonStr)
const jsObj2 = JSON.parse(jsonStr, (key, value) => {
  if (key === 'birthday') {
    return new Date(value).getTime()
  } else {
    return value
  }
})

console.log(jsObj1) // {name: "Tom", birthday: "2020-01-01"}
console.log(jsObj2) // {name: "Tom", birthday: 1577836800000}

JavaScript 内置的全局函数 eval() 可以用来计算,也可以解析 JSON,如 eval('(' + jsonStr + ')'),但由于该函数是不安全的,不推荐使用。

JSON.stringify()

JSON.stringify() 函数用于 JSON 序列化,即将一个 JavaScript 对象转换成一个 JSON 字符串。

语法:JSON.stringify(value[, replacer[, space]])

  • value:必需, 要转换的 JavaScript 值(通常为对象或数组)。
  • replacer:可选。用于转换结果的函数或数组。
    • 如果 replacer 为函数,则 JSON.stringify 将调用该函数,并传入每个成员的键和值。使用返回值而不是原始值。如果此函数返回 undefined,则排除成员。根对象的键是一个空字符串。
    • 如果 replacer 是一个数组,则仅转换该数组中具有键值的成员。成员的转换顺序与键在数组中的顺序一样。当 value 参数也为数组时,将忽略 replacer 数组。
  • space:可选,将缩进、空格和换行符添加到返回的 JSON 文本中,使其更易于阅读。
    • 如果 space 是一个数字,则返回值文本在每个级别缩进指定数目的空格(如果 space 大于 10,则只缩进 10 个空格)。
    • space 也可以使用非数字,如:\t
const jsObj = { name: 'Tom', birthday: '2020-01-01' }
const jsArr = ['Google', 'Runoob', 'Taobao', 'Facebook']

const jsonStr1 = JSON.stringify(jsObj) // 序列化 JS 对象
const jsonStr2 = JSON.stringify(jsArr) // 序列化 JS 数组
const jsonStr3 = JSON.stringify(jsObj, ['name'])
const jsonStr4 = JSON.stringify(jsObj, (key, value) => {
  if (key === 'birthday') {
    return new Date(value).getTime()
  } else {
    return value
  }
}, 4)

console.log(jsonStr1) // {"name":"Tom","birthday":"2020-01-01"}
console.log(jsonStr2) // ["Google","Runoob","Taobao","Facebook"]
console.log(jsonStr3) // {"name":"Tom"}
console.log(jsonStr4)
// {
//     "name": "Tom",
//     "birthday": 1577836800000
// }

当我们直接进行对象拷贝时,实际上是拷贝了该对象的引用地址,改变其中一个对象,另外一个也会改变。我们可以使用 JSON.parse(JSON.stringify(obj)) 来进行 对象深拷贝,但是这种方式有一定局限性,例如无法正确处理 Date、RegExp、Error 等对象。

JSON Schema

JSON Schema 描述了 JSON 文件的数据格式、值集、默认值和描述,可以帮助编辑器(如 IDEA、WebStorm、VS Code 等)进行智能提示和验证功能。JSON Schema Store 中给提供了 300 多种 JSON 文件的 JSON Schemas 定义,可以直接使用,你也可以定义自己的 JSON Schemas 格式。

images

下面演示如何在 VS Code 中管理 JSON Schema:

在 VSCode 中配置 JSON schema 后,可以在写 JSON 的时候出现智能提示:

"json.schemas": [
  {
    "fileMatch": [".prettierrc"],
    "url": "http://json.schemastore.org/prettierrc"
  }
]

或者在 JSON 文件内部定义(可能会验证失败):、

{
  "$schema": "http://json.schemastore.org/coffeelint",
  "line_endings": "unix"
}

JSON schema 加载成功:

images

JSON schema 加载失败:

images images

JSON 扩展库

JSONC(JSON with Commits)

JSONC 是 JSON 的超集,支持单行和多行注释,提高了 JSON 文件可读性。VS Code 在其配置文件(例如 settings.json、keybindings.json、launch.json 等)中也使用此格式。

相关库:

{
    // comment
    "data": /* comment */ "value"
}

JSON5

github.com/json5/json5

JSON5 是 JSON 的超集,让 JSON 语法更接近 JavaScript 语法。主要扩展了以下功能:

  • 支持单行和多行注释(comments)。
  • 键名(name)不需要用双引号引起来了。
  • 字符串可以用单引号(single quoted)引起来了。
  • 字符串可以包含字符转义符(character escapes),并且可以通过转义换行符来跨越多行。
  • 对象和数组支持尾随逗号(trailing comma)。

示例:

{
  // comments
  unquoted: 'and you can quote me on that',
  singleQuotes: 'I can use "double quotes" here',
  lineBreaks: "Look, Mom! \
No \\n's!",
  hexadecimal: 0xdecaf,
  leadingDecimalPoint: .8675309,
  andTrailing: 8675309.,
  positiveSign: +1,
  trailingComma: 'in objects',
  andIn: ['arrays',],
  "backwardsCompatible": "with JSON",
}

如何使用?

JSON5 API 与标准的 JSON API 兼容,也提供了 parse()stringify() 两个方法。

Browsers:

<script src="https://unpkg.com/json5@^2.0.0/dist/index.min.js"></script>

Node.js:

npm install json5
const fs = require('fs')
const path = require('path')
const JSON5 = require('json5')

const filePath = path.join(__dirname, '../assets/test.json5')
const content = fs.readFileSync(filePath, 'utf-8')

JSON5.parse(JSON5.stringify(content))

另外,推荐安装 VS Code 插件 JSON5 syntax,它提供了对 .json5 文件的语法高亮支持。

Hjson

github.com/hjson/hjson

Hjson 是 JSON 的语法扩展,支持以下特性:

  • 支持注释
  • 支持多行文本
  • 支持尾逗号,并且尾逗号是可选的
  • 键名可以不带引号
  • 键值是字符串时可以不带引号

相关库:

{
  // use #, // or /**/ comments,
  // omit quotes for keys
  key: 1
  // omit quotes for strings
  contains: everything on this line
  // omit commas at the end of a line
  cool: {
    foo: 1
    bar: 2
  }
  // allow trailing commas
  list: [
    1,
    2,
  ]
  // and use multiline strings
  realist:
    '''
    My half empty glass,
    I will fill your empty half.
    Now you are half full.
    '''
}

配置文件解决方案

配置文件是一种非常基础的文件格式,它不需要像其他格式那样复杂,如数据文件格式(如 SQLite)、文档文件格式(如 Markdown)、编程语言格式(如 JavaScript)、甚至二进制文件格式(如 PNG)等。

配置文件最基本的诉求就是易读、易编写和易解析,但就这样一种简单的需求,却长期以来一直没有一种足够好的通用文件格式。

JSON

JSON(.json)是一种非常友好的数据传输格式,在前端项目中被大量使用,如 npm 和 yarn 使用的 package.json。

JSON 不支持注释、不支持多行文本、不支持尾逗号等特性,如果需要,可以使用 JSON 扩展库 JSON5 或 JSONC。

{
  "description": "This is an example.",
  "env": {
    "node": false,
    "browser": true
  },
  "sites": [
    { "name": "Apple", "url": "www.apple.com" },
    { "name": "Google", "url": "www.google.com" },
    { "name": "Facebook", "url": "www.facebook.com" }
  ]
}

XML

XML(.xml)是一种较为通用的配置文件格式,易读、易解析,支持嵌套结构,支持数组形式。可以被大多数编程语言使用,在 Java Spring 项目中被大量使用。

与 JSON 相比,XML 不够优雅,数值需要被包裹在开始标签和结束标签直接,文档 size 也更大。JSON 读写速度更快,可以直接在 JS 中使用,XML 需要使用 XML 解析器来解析。

<?xml version="1.0" encoding="UTF-8" ?>
<description>This is an example.</description>
<env>
    <node>false</node>
    <browser>true</browser>
</env>
<sites>
    <name>Apple</name>
    <url>www.apple.com</url>
</sites>
<sites>
    <name>Google</name>
    <url>www.google.com</url>
</sites>
<sites>
    <name>Facebook</name>
    <url>www.facebook.com</url>
</sites>

YAML

github.com/yaml/yaml

YAML(.yml)是一种“现代化”的配置文件格式,它使用严格的缩进语法表示层级关系,支持注释,支持对象、数组等数据结构,也支持引用文件。YAML 的主要缺点是规范比较复杂,不同的实现之间可能存在不一致的情况。

YAML 配置文件在 CI/CD 项目中会经常遇到(如 Travis CI、Circle CI、Docker Compose 等)。

# This is a TAML document
description: This is an example.
env:
  node: false
  browser: true
sites:
  - name: Apple
    url: www.apple.com
  - name: Google
    url: www.google.com
  - name: Facebook
    url: www.facebook.com

相关库:

TOML

TOML(.toml)也是一种“现代化”的配置文件格式,该格式易于阅读,也易于解析为多种语言的数据结构。

与 JSON 相比,TOML 支持注释;与 YAML 相比,TOML 更加简洁。

Gitlab Runner 的配置文件就是使用的 YAML 格式。

# This is a TOML document

title = "TOML Example"

[owner]
name = "Tom Preston-Werner"
dob = 1979-05-27T07:32:00-08:00

[database]
enabled = true
ports = [ 8001, 8001, 8002 ]
data = [ ["delta", "phi"], [3.14] ]
temp_targets = { cpu = 79.5, case = 72.0 }

[servers]

[servers.alpha]
ip = "10.0.0.1"
role = "frontend"

[servers.beta]
ip = "10.0.0.2"
role = "backend"

如何使用?

# https://github.com/BinaryMuse/toml-node
npm install toml
const fs = require('fs')
const path = require('path')
const toml = require('toml')

const filePath = path.join(__dirname, '../assets/test.toml')
const content = fs.readFileSync(filePath, 'utf-8')

toml.parse(content)

另外,推荐安装 VS Code 插件 Better TOML,它提供了对 .toml 文件的语法高亮支持。

HOCON

github.com/lightbend/c…

HOCON(Human-Optimized Config Object Notation)是一个灵活且易于使用的配置文件格式,甚至还支持重用和继承等 OO 语言才支持的功能,常被用于 Nginx、Java、Scala 等项目中,文件扩展名是 .conf

jdbc {
  diver = "com.mysql.jdbc.Driver"
  url = "jdbc:mysql://host:3306/database?useUnicode=true&characterEncoding=UTF-8"
  username = "root"
  password = "1234"
}

properties

properties(.properties)是一种非常简单的配置文件格式,主要在 Java 相关技术中用来存储应用程序的可配置参数。

每个参数被存储为一个“键值对”,每一行通常存储单个参数。

jdbc_diver="com.mysql.jdbc.Driver"
jdbc_url=jdbc:mysql://localhost:3306/test
jdbc_username=root
jdbc_password=1234

INI

INI(.ini)是一种非常原始的配置文件格式,在 Windows 操作系统中非常常见。

它只适用于非常简单的配置,最多只能解决一层嵌套,一旦需要多层嵌套,或需要数组时,就力不从心了。

; 最简单的结构

a = a;
b = b; 这些等号后面的值是字符串(句末分号不是必须的;它后面的都是注释)

; 稍微复杂一点的单层嵌套结构

[c]
x = c.x
y = c.y

[d]
x = d.x
y = d.y

一些实用的在线工具

参考资料

  1. JSON www.json.org/json-zh.htm…
  2. JSON 教程 | 菜鸟教程 www.runoob.com/json/json-t…
  3. JSON - JavaScript | MDN developer.mozilla.org/zh-CN/docs/…
  4. YAML 语言教程 - 阮一峰的网络日志 www.ruanyifeng.com/blog/2016/0…