JSON 简介
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于阅读和编写,并且容易被多种编程语言解析和生成。
编写 demo.json 文件:
{
"name": "John",
"age": 30,
"isMarried": false,
"hobbies": ["reading", "hiking", "photography"],
"address": {
"city": "New York",
"country": "USA"
}
}
JSON 方法
在 JS 中,可以使用 JSON.parse()
将 JSON 字符串转换为 JS 对象,使用 JSON.stringify()
将 JS 对象转换为 JSON 字符串。
parse 是 “解析” 的意思;stringify 是 “字符串化” 的意思。
const obj = {
name: 'superman',
age: 21,
isMarried: false,
hobbies: ['basketball'],
brother: { name: 'monster' },
children: null,
};
const jsonStr = JSON.stringify(obj);
console.log(jsonStr);
const newObject = JSON.parse(jsonStr);
console.log(newObject);
JSON.stringify 的使用
特殊的第一参数
- 直接忽略的情况:
const age = Symbol('age');
const person = {
_function: function () {}, // 函数 → 直接忽略
_undefined: undefined, // undefined → 直接忽略
[age]: 30, // symbol → 直接忽略
};
// 不可枚举属性 → 直接忽略
Object.defineProperty(person, 'car', {
value: 'BMW',
enumerable: false,
});
// 继承属性 → 直接忽略
const obj = { living: true };
Object.setPrototypeOf(person, obj);
console.log(JSON.stringify(person)); // {}
- 处理为 null 的情况:
const obj = {
_null: null, // null → 返回 null
_NaN: NaN, // NaN → 返回 null
_Infinity1: Infinity, // Infinity → 返回 null
_Infinity2: -Infinity, // -Infinity → 返回 null
};
console.log(JSON.stringify(obj)); // {"_null":null, "_NaN":null, "_Infinity1":null, "_Infinity2":null}
- 其他情况:
const obj = {
_RegExp: new RegExp(), // 正则 → 返回空对象 {}
_Date: new Date(), // Date → 以字符串形式返回
};
console.log(JSON.stringify(obj)); // {"_RegExp":{}, "_Date":"2023-08-01T03:10:18.011Z"}
在数组中遇到 undefined、function 和 symbol 时会返回 null(以保证单元位置不变)。
JSON.stringify([1, undefined, function () {}, 4]); // "[1, null, null,4]"
JSON.stringify({ a: 2, b: function () {} }); // "{"a":2}"
对包含循环引用的对象执行 JSON.stringify(..)
会出错。
第二参数
JSON.stringify 可传入 array
作为第 2 参数,表示获取指定属性:
const obj = {
name: 'superman',
age: 21,
gender: 'male',
address: 'China',
};
console.log(JSON.stringify(obj, ['name', 'gender'])); // {"name":"superman", "gender":"male"}
JSON.stringify 可传入 callback
作为第 2 参数,以获取函数处理后的数据:
const a = {
b: 42,
c: '42',
d: [1, 2, 3],
};
JSON.stringify(a, ['b', 'c']); // '{"b":42, "c":"42"}'
JSON.stringify(a, function (k, v) {
if (k !== 'c') return v;
}); // '{"b":42, "d":[1,2,3]}'
callback
的参数 k
在第一次调用时为 undefined
(就是对对象本身调用的那次)。由于字符串化是递归的,因此数组 [1,2,3]
中的每个元素都会通过参数 v
传递给 callback
,即 1
、2
和 3
,参数 k
是它们的索引值,即 0
、1
和 2
。
第三参数
JSON.stringify 可传入 space
作为第 3 参数,用于美化格式。space
为正整数时是指定每一级缩进的字符数,它还可以是字符串,此时最前面的十个字符被用于每一级的缩进:
const a = {
b: 42,
c: '42',
d: [1, 2, 3],
};
JSON.stringify(a, null, 3);
// "{
// "b": 42,
// "c": "42",
// "d": [
// 1,
// 2,
// 3
// ]
// }"
JSON.stringify(a, null, '-----');
// "{
// -----"b": 42,
// -----"c": "42",
// -----"d": [
// ----------1,
// ----------2,
// ----------3
// -----]
// }"
自定义 stringify
如果对象中定义了 toJSON()
,JSON 字符串化时会首先调用该方法,然后用它的返回值来进行序列化。
const a = { b: 42, c: '42' };
// 自定义的 JSON 序列化
a.toJSON = function () {
// 序列化仅包含 b
return { b: this.b };
};
JSON.stringify(a); // '{"b":42}'
const obj = {
name: 'superman',
hobbies: ['basketball', 'football'],
age: 21,
toJSON() {
return `${this.name}, ${this.hobbies}, ${this.age}`;
},
};
console.log(JSON.stringify(obj)); // "superman, basketball,football, 21"
使用场景
- 配合 localStorage 使用:
const obj = { name: 'superman' };
localStorage.setItem('obj', JSON.stringify(obj));
const objStr = localStorage.getItem('obj');
- 深拷贝比较简单的对象:
const obj = {
name: 'superman',
hobbies: ['basketball', 'football'],
age: 21,
};
const objDeepCopy = JSON.parse(JSON.stringify(obj));
objDeepCopy.hobbies[0] = 'swimming';
console.log(obj); // {name:'superman', hobbies:['basketball','football'], age:21}
console.log(objDeepCopy); // {name:'superman', hobbies:['swimming','football'], age:21}
- 删除对象的指定属性:
const obj = {
name: 'superman',
hobbies: ['basketball', 'football'],
age: 21,
};
const deleteProperty = (obj, prop) => {
const jsonStr = JSON.stringify(obj, (key, value) => {
if (key === prop) {
return undefined; // stringify 会忽略值为 undefined 的属性
}
return value;
});
return JSON.parse(jsonStr);
};
const newObj = deleteProperty(obj, 'hobbies');
console.log(newObj); // { name:'superman', age:21 }