在JavaScript语言中,JSON(JavaScript Object Notation)已经成为了数据存储和传输的标准。 JSON可以轻松地将数据对象变成字符串,在不同的设备之间进行数据的传输和共享,是非常实用的一种数据格式。而json.stringify()则是JSON中的一个非常重要的方法,它能够将JavaScript中的数据对象变成字符串,并且可以进行格式化并添加缩进,使得读取数据更加简单和易懂。
那么,本篇文章就在json.stringify()上进行介绍和学习,深入探究json.stringify()方法的实现原理及常用的语法知识和技巧。
## 了解json.stringify()方法
JSON.stringify() 可以将一个 JavaScript 对象或值转换为 JSON 字符串。这个方法是 JSON 对象上的方法,可以将 JSON 格式的数据对象编码成字符串,以便通过网络进行传输或其他用途。
### 语法格式
JSON.stringify(value[, replacer [, space]])
- value:必选项,必须传对象或数组,表示要序列化为 JSON 字符串的值。
- replacer:可选项,可以是函数或数组,用于规定对象序列化成 JSON 字符串时需要转换的值。如果是一个函数,那么就会遍历对象的每一个属性并将其转换为字符串。这个函数会接收两个参数:属性名称和属性值。返回的值将用作对象值的 JSON 字符串形式。如果是一个数组,那么只有存在于数组中的属性才会被序列化成 JSON 字符串。
- space:可选项,表示输出格式化缩进和间距用来控制生成的字符串缩进的格式。它可以是一个数字、字符串,也可以是一个全等于 2 或 4 的空格字符串。当该参数缺省时,生成的 JSON 字符串不会格式化缩进。
### 常用的使用方式
JSON.stringify()方法具有很多的应用场景,接下来就将一些常见的应用场景进行介绍:
#### 序列化对象
当我们需要将一个对象序列化成 JSON 字符串时,就需要使用到JSON.stringify()方法,例如下面的代码:
```javascript
var myObj = {
"name": "Jack",
"age": 18,
"gender": "male",
"address": {
"city": "Beijing",
"country": "China"
}
};
var jsonString = JSON.stringify(myObj)
console.log(jsonString);
```
输出结果如下:
```javascript
{
"name":"Jack",
"age":18,
"gender":"male",
"address":{
"city":"Beijing",
"country":"China"
}
}
```
#### 序列化数组
同样的,我们也可以将一个数组序列化成 JSON 字符串,例如下面的代码:
```javascript
var myArr = ["apple", "banana", "orange"];
var jsonString = JSON.stringify(myArr)
console.log(jsonString);
```
输出结果如下:
```javascript
["apple","banana","orange"]
```
#### 序列化自定义对象
当我们需要将一个自定义对象序列化为JSON字符串时,我们可以使用JSON.stringify()方法来进行操作。例如下面的代码:
```javascript
function student(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
var myObj = new student("Jack", 18, "male");
var jsonString = JSON.stringify(myObj)
console.log(jsonString);
```
输出结果如下:
```javascript
{"name":"Jack","age":18,"gender":"male"}
```
#### 序列化日期对象
日期对象本身不能直接序列化成JSON字符串,因为JSON规范中没有对日期格式的统一标准,但是可以通过一些技巧将日期对象序列化成字符串,例如下面的代码:
```javascript
var date = new Date();
var jsonString = JSON.stringify(date, (key, value) => {
if (typeof value === 'object') {
if (value instanceof Date) {
return value.toLocaleDateString()
}
}
return value
})
console.log(jsonString)
```
输出结果如下:
```javascript
"2022/3/23"
```
#### 使用replacer参数创建自定义的JSON对象
我们可以使用replacer参数来指定JSON.stringify()方法转换时的某些操作。例如,下面的代码将删除myObj对象中的属性age:
```javascript
var myObj = {
"name": "Jack",
"age": 18,
"gender": "male"
};
var jsonString = JSON.stringify(myObj, function(key, value) {
if (key === "age") {
return undefined;
}
return value;
});
console.log(jsonString);
```
输出结果如下:
```javascript
{"name":"Jack","gender":"male"}
```
这个参数还可以接收一个数组,其中包含要序列化成JSON字符串的属性名称。例如下面代码,序列化myObj对象中的name和age属性:
```javascript
var myObj = {
"name": "Jack",
"age": 18,
"gender": "male"
};
var jsonString = JSON.stringify(myObj, ["name", "age"]);
console.log(jsonString);
```
输出结果如下:
```javascript
{"name":"Jack","age":18}
```
#### 使用space参数创建格式化的JSON字符串
我们也可以通过使用space参数生成格式化缩进的JSON字符串,例如下面的代码:
```javascript
var myObj = {
"name": "Jack",
"age": 18,
"gender": "male"
};
var jsonString = JSON.stringify(myObj, null, 4);
console.log(jsonString);
```
输出结果如下:
```javascript
{
"name": "Jack",
"age": 18,
"gender": "male"
}
```
## json.stringify()方法的实现原理
了解完json.stringify()方法的常见使用方式,我们接着来看一下json.stringify()方法的实现原理。在理解这个过程之前,先来看一下什么是序列化和什么是反序列化。
### 序列化
序列化指将一种数据格式转化为另一种数据格式的过程,例如将一个JavaScript对象转化为JSON字符串的过程。序列化可以将各种类型的数据结构转换成JSON格式,以方便网络传输或在不同语言之间进行数据通讯。
### 反序列化
反序列化是指将一个序列化后的数据格式解码回原来的数据格式的过程,例如将一个JSON字符串反序列化为JavaScript对象的过程。
而在json.stringify()方法中,根据传入的对象和参数,方法会将传入对象中的信息递归地按照 JSON 的规则逐层解析成字符串,并返回解析成功的字符串。具体实现原理如下:
- 如果传入的对象为原始类型(null,undefined,boolean,number,string),那么直接返回其对应的字符串。
- 如果传入的对象为数组,则先遍历数组中的元素,将每个元素递归应用 json.stringify(),生成对应的 JSON 字符串,然后使用 "[]" 拼接成字符串并返回。
- 如果传入的对象为对象(除数组),则遍历对象自有属性,为每个属性的值进行递归操作,生成对应的 JSON 字符串。如果某个属性的值为 undefined,函数会将其忽略。最终,使用 "{}" 拼接成字符串并返回。
- 如果replacer参数传递了一个函数,那么在遍历对象自有属性的时候,将该函数分别应用于每一个属性,并返回所处理的结果。如果返回值为 undefined,则忽略该属性。如果返回值为对象,则继续将返回值作为参数进行递归处理。最终得到一个新的对象,该对象只保留 replacer 函数返回值对象所描述的属性。
- 如果space参数传递了一个字符串,那么在生成 JSON 字符串的过程中使用该字符串来对其进行格式化缩进处理。
最后我们可以对以上过程进行简单的伪代码描述:
```javascript
function jsonStringify(obj, replacer, space) {
let JSONString = '';
const isArray = Array.isArray(obj);
// 如果传入的对象为原始数据类型,直接返回其对应的字符串
if (typeof obj === 'boolean' || typeof obj === 'number' || typeof obj === 'string' || obj === null || obj === undefined) {
return String(obj);
}
if (isArray) { // 如果传入的对象为数组
JSONString = '[';
for (let i = 0; i < obj.length; i++) {
// 序列化数组中的每一项,并添加逗号分隔符
const itemString = jsonStringify(obj[i], replacer, space);
JSONString += `${(itemString === undefined ? null : itemString)},`;
}
// 去掉最后一个逗号分隔符
JSONString = JSONString.substring(0, JSONString.length - 1);
JSONString += ']';
} else { // 如果传入的对象为对象
JSONString = '{';
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 如果replacer参数传递了一个函数
if (replacer) {
const res = replacer(key, obj[key]);
if (res === undefined) {
continue;
}
JSONString += `"${key}":${jsonStringify(res, replacer, space)},`;
} else {
JSONString += `"${key}":${jsonStringify(obj[key], replacer, space)},`;
}
}
}
// 去掉最后一个逗号分隔符
JSONString = JSONString.substring(0, JSONString.length - 1);
JSONString += '}';
}
// 如果space参数传递了一个字符串,使用该字符串来对JSON字符串进行格式化缩进
if (space) {
const indent = space + ' ';
const newline = '\n';
let i = 0, j = 0;
while (i <= JSONString.length) {
if (JSONString[i] === '{' || JSONString[i] === '[') {
j++;
JSONString = `${JSONString.substring(0, i + 1)}${newline}${indent.repeat(j)}${JSONString.substring(i + 1)}`
i += 2 + j * space.length;
} else if (JSONString[i] === '}' || JSONString[i] === ']') {
j--;
JSONString = `${JSONString.substring(0, i)}${newline}${indent.repeat(j)}${JSONString.substring(i)}`
i += 1 + j * space.length;
} else if (JSONString.substring(i, i + newline.length) === newline) {
i += newline.length;
} else {
i++;
}
}
}
return JSONString;
}
```
## 总结
在JavaScript中,JSON已经成为了数据存储和传输的标准,而json.stringify()方法是JSON中非常重要的方法之一,能够将JavaScript中的数据对象变成字符串,并且可以进行格式化并添加缩进,使得读取数据更加简单和易懂。 在不同的应用场景下,我们可以使用该方法来序列化对象、数组、日期对象和自定义对象等,也可以使用replacer参数和space参数来进行自定义的操作和创建格式化的JSON字符串。同时,通过理解json.stringify()方法的实现原理,有助于我们加深对JSON这一数据存储和传输标准的理解,更好地运用于实际开发中。