JSON 的由来
在目前的开发中,JSON是一种非常重要的数据格式,它并不是编程语言,而是一种可以在服务器和客户端之间传输的数据格式。
JSON 的全称是 JavaScript Object Notation(JavaScript对象符号):
- JSON 是由 Douglas Crockford 构想和设计的一种轻量级资料交换格式,算是 JavaScript 的一个子集;
- 但是虽然 JSON 被提出来的时候是主要应用 JavaScript 中,但是目前已经独立于编程语言,可以在各个编程语言中使用;
- 很多编程语言都实现了将 JSON 转成对应模型的方式;
其他的传输格式:
- XML:在早期的网络传输中主要是使用XML来进行数据交换的,但是这种格式在解析、传输等各方面都弱 JSON,所以目前已经很少在被使用了;
- Protobuf:另外一个在网络传输中目前已经越来越多使用的传输格式是protobuf,但是直到2021年的3.x版本才支持JavaScript,所以目前在前端使用的较少;
目前JSON被使用的场景也越来越多:
- 简单值:数字(Number)、字符串(String,不支持单引号)、布尔类型(Boolean)、null 类型; ```json 123
这样是错误的,json 的顶层只能有一个,json 中也不能添加注释 123 “hhh”
2. 对象值:由key、value组成,key是字符串类型,并且必须添加双引号,值可以是简单值、对象值、数组值;
```json
{
"name": "zs",
"arr": [1, 2, 3],
"obj": {
"age": 123
} 最后一个键值对不能有逗号结尾
}
- 数组值:数组的值可以是简单值、对象值、数组值;
[
123,
"hhh",
[1, 2, 3],
{
"name": "zs"
}
]
JSON 序列化
我们传输或存储数据处理的都是字符串,比如要存储一个对象到本地存储中,存储的其实是对象的字符串形式。
但是我们存储对象的时候会发现,直接存储对象,对象自动转成的字符串是 [object Object] ,这并不是我们想要的。 ```javascript const obj = { name: ‘zs’, run() { console.log(this.name + ‘ running’) } }
localStorage.setItem(“obj”, obj) console.log( localStorage.getItem(“obj”) ) // [object Object]
所以我们可以利用 json 格式,做一个中间转化。
在 ES5 中引用了 JSON 全局对象,该对象有两个常用的方法:
- stringify 方法:将 JavaScript 类型转成对应的 JSON 字符串;
- parse 方法:解析 JSON 字符串,转回对应的 JavaScript 类型;
<a name="d5ugg"></a>
## JSON.stringify( )
`JSON.stringify()`方法将一个 JavaScript 对象 或 值 转换为 JSON 字符串。它能接收三个参数。
- 注意:**JSON 本质是来存储数据的,而函数是种行为,所以 JSON 不支持函数。**
- **所以 stringify 函数会把对象中的函数过滤掉**
```javascript
const obj = {
name: "why",
age: 18,
friends: {
name: "kobe"
},
hobbies: ["篮球", "足球"],
sing: function() { // 函数将会被过滤
console.log(this.name + ' singing')
}
}
// 需求: 将上面的对象转成JSON字符串
// 1.直接转化
const jsonString1 = JSON.stringify(obj)
console.log(jsonString1)
// {"name":"why","age":18,"friends":{"name":"kobe"},"hobbies":["篮球","足球"]}
// 2.stringify第二个参数replacer
// 2.1. 传入数组: 指定哪些键值对是需要转换
const jsonString2 = JSON.stringify(obj, ["name", "friends"])
console.log(jsonString2)
// {"name":"why","friends":{"name":"kobe"}}
// 2.2. 传入回调函数: 可以对字符串进行过滤
const jsonString3 = JSON.stringify(obj, (key, value) => {
if (key === "age") { // 将 age 的 value 值 +1
return value + 1
}
return value
})
console.log(jsonString3)
// {"name":"why","age":19,"friends":{"name":"kobe"},"hobbies":["篮球","足球"]}
// 3.stringify第三个参数 space,对json字符串进行格式化
// 数字:表示在键值对前填充空格个数;字符串:填充字符串
const jsonString4 = JSON.stringify(obj, null, 2)
console.log(jsonString4)
// {
// "name": "why",
// "age": 18,
// "friends": {
// "name": "kobe"
// },
// "hobbies": [
// "篮球",
// "足球"
// ]
// }
若对象中有toJSON()
函数,则stringify()
只会将 toJSON 的返回值转成 JSON 字符串。换句话说对象可以使用 toJSON 函数指定转成后的 JSON 字符串。
const obj = {
name: "why",
age: 18,
friends: {
name: "kobe"
},
hobbies: ["篮球", "足球"],
toJSON: function() {
return "123456"
}
}
// 4.如果obj对象中有toJSON方法
const jsonString1 = JSON.stringify(obj)
console.log(jsonString1) // "123456"
JSON.parse( )
JSON.parse()
方法用来解析 JSON 字符串,构建由字符串描述的 JavaScript 值 或 对象。
const JSONString = '{"name":"why","age":19,"friends":{"name":"kobe"},"hobbies":["篮球","足球"]}'
const info1 = JSON.parse(JSONString)
console.log(info1)
// {
// name: 'why',
// age: 19,
// friends: { name: 'kobe' },
// hobbies: [ '篮球', '足球' ]
// }
// 第二个参数:为可选的 reviver 函数,可以在返回之前对所得到的对象执行变换(操作)
const info2 = JSON.parse(JSONString, (key, value) => {
if (key === "age") {
return value - 1
}
return value
})
console.log(info2)
// {
// name: 'why',
// age: 18,
// friends: { name: 'kobe' },
// hobbies: [ '篮球', '足球' ]
// }
使用 JSON 序列化进行深拷贝
引用赋值、浅/深拷贝
有三种常见的复制方式。
- 引用赋值是最普通的一种复制,只是复制了堆内存的地址,两个引用共享一块堆内存。
浅拷贝和深拷贝主要针对于那些存在引用属性的对象,也就是存在引用的引用。
- 浅拷贝就是只复制了那些引用属性保存的引用也就是堆内存的地址。
- 深拷贝就是更深,复制到了引用属性所指向的堆内存上那些内容。
JSON.parse()
从字符串还原成对象的时候,内存都是重新开辟的,所以相当于进行了一次深拷贝。但是由于 JSON 的局限性,对象中函数被舍弃了,所以深拷贝了,但没完全深拷贝。
const obj = {
name: "why",
age: 18,
friends: {
name: "kobe"
},
hobbies: ["篮球", "足球"],
foo: function() {
console.log("foo function")
}
}
// 将obj对象的内容放到info变量中
// 1.引用赋值
const info = obj
obj.age = 100 // obj info 指向同一个地址
console.log(info.age) // 100
// 2.浅拷贝
// 可以手动给 info2 动态添加 obj 的属性,也可以使用展开运算符添加
const info2 = { ...obj }
obj.age = 1000 // 基本属性是真正的拷贝了
console.log(info2.age) // 100
obj.friends.name = "james" // 引用属性也只是复制了堆内存地址
console.log(info2.friends.name) // james
// 3.stringify和parse来实现深拷贝
const jsonString = JSON.stringify(obj)
// JSON 的缺陷,函数被过滤掉了,导致复制不了函数
console.log(jsonString)
// {"name":"why","age":1000,"friends":{"name":"james"},"hobbies":["篮球","足球"]}
const info3 = JSON.parse(jsonString)
obj.friends.name = "curry" // 重新开辟了内存,互不影响
console.log(info3.friends.name) // james
Storage
WebStorage 主要提供了一种机制,可以让浏览器提供一种比 cookie 更直观的key、value存储方式:
localStorage
:本地存储,提供的是一种永久性的存储方法,在关闭掉网页重新打开时,存储的内容依然保留;sessionStorage
:会话存储,提供的是本次会话的存储,在关闭掉会话时,存储的内容会被清除;
localStorage 和 sessionStorage 的区别
因为 localStorage 是永久存储,而一个网页窗口就是一个会话,所以关闭网页后重新打开,localStorage 会保留,而 sessionStorage 会被删除。
在页面内实现跳转,并没有新开窗口,所以 localStorage 会保留,sessionStorage 也会保留。在页面外实现跳转(打开新的网页),localStorage 会保留,sessionStorage 不会被保留;
Storage 常见的方法和属性
localStorage 和 sessionStorage 的方法和属性是一样的。
属性:
Storage.length
:只读属性- 返回一个整数,表示存储在 Storage 对象中的数据项数量;
方法:
Storage.key()
:该方法接受一个数值 n 作为参数,返回存储中的第 n 个 key 名称;Storage.getItem()
:该方法接受一个 key 作为参数,并且返回 key 对应的 value;Storage.setItem()
:该方法接受一个 key 和 value,并且将会把 key 和 value 添加到存储中。- 如果 key 已经存在,则更新其对应的值;
Storage.removeItem()
:该方法接受一个key作为参数,并把该key从存储中删除;Storage.clear()
:该方法的作用是清空存储中的所有key; ```javascript // 1.setItem localStorage.setItem(“name”, “zs”) localStorage.setItem(“age”, 18)
// 2.length console.log(localStorage.length) for (let i = 0; i < localStorage.length; i++) { const key = localStorage.key(i) console.log(localStorage.getItem(key)) }
// 3.key方法 console.log(localStorage.key(0))
// 4.getItem(key) console.log(localStorage.getItem(“age”))
// 5.removeItem localStorage.removeItem(“age”)
// 6.clear方法 localStorage.clear()
因为两个存储的方法和属性都是一样的,所以可以封装一个工具类,统一使用。
```javascript
class HYCache {
constructor(isLocal = true) {
this.storage = isLocal ? localStorage: sessionStorage
}
setItem(key, value) {
if (value) {
this.storage.setItem(key, JSON.stringify(value))
}
}
getItem(key) {
let value = this.storage.getItem(key)
if (value) {
value = JSON.parse(value)
return value
}
}
removeItem(key) {
this.storage.removeItem(key)
}
clear() {
this.storage.clear()
}
key(index) {
return this.storage.key(index)
}
length() {
return this.storage.length
}
}
const localCache = new HYCache()
const sessionCache = new HYCache(false)
export {
localCache,
sessionCache
}