我们知道,localStorage
只接受字符串类型的键值,因此当我们需要存储引用类型时,需要先进行序列化。
先来看一下不进行序列化会有什么问题:
let obj = {
name: "dby",
age: 12,
sex: 0
}
localStorage.setItem("user", obj);
打开 Chrome 开发者工具,选择 Application
,然后点 localStorage
,可以看到刚才存进去的 user
字段,该字段的值变成了 [object Object]
。这说明 localStorage
在存储的时候,对于非字符串的值,会尝试调用 toString
方法转为字符串,但是 Object
类型调用 toString
只会输出对象的内部属性 [object Object]
。
同理,对于 Array 类型,直接存进去也会调用 toString
方法:
localStorage.setItem("user", [1, 2, 3, 4]);
因此,当需要用 localStorage
存储引用类型的值,需要用 JSON.stringify
方法进行序列化。
let obj = {
name: "dby",
age: 12,
sex: 0
}
localStorage.setItem("user", JSON.stringify(user));
在实际开发中,通常会对这个操作进行封装,下面介绍一下常用的处理方法。
本地存储方法封装
这边封装了两个方法 storageSet
和 storageGet
。
function storageSet(key, value) {
if (value instanceof Object) {
// 引用类型,包括 Object 和 Array
localStorage.setItem(key, JSON.stringify(value));
} else {
// 基本类型直接存储
// 注意如果不是 string 类型,则会调用 toString 方法尝试转为 string
localStorage.setItem(key, value);
}
}
function storageGet(key) {
let str = localStorage.getItem(key);
try {
// 如果值不是 JSON 对象,会导致反序列化失败,因此这边用 try catch 包裹一下
return JSON.parse(str);
} catch (error) {
// 不是 JSON 对象,直接返回字符串
return str;
}
}
这边有两个注意点:
1. 判断引用类型,这边用了 instanceof
,当然也可以使用 typeof value == "object"
进行判断,只不过 null
也会被判断为 true
;
2. 如果值不是 JSON 对象,调用 JSON.parse
会导致反序列化失败,因此这边用了 try catch 包裹一下;
3. 在 JSON 序列化的时候,会忽略 undefined
、symbol 值和函数,因此对象中最好不要包含这些类型;
重写对象的 toString 方法
在面向对象编程中有一大特征叫做多态,既然对象的 toString
方法会返回 [object Object]
,那么如果我们重写对象的 toString
方法,就可以避免输出对象的内部属性了。
重写有几种方式,但是像下面这样直接覆盖是不推荐的,会导致原型链污染:
Object.prototype.toString = function() {
...
}
有一种简单的方法,直接在对象里面添加 toString
方法:
let obj = {
name: "dby",
age: 12,
sex: 0,
toString() {
return JSON.stringify(this);
}
}
obj.toString();
// "{\"name\":\"dby\",\"age\":12,\"sex\":0}"
刚才说了 JSON 序列化的时候会忽略函数,因此我们添加的 toString
方法并不会出现在结果里面。
还有一种就是我们创建一个类,然后用这个类去继承 Object 类,在这个类中重写 toString
方法:
class MyObject extends Object {
@Override
toString() {
return JSON.stringify(this);
}
}
注意这个时候我们创建对象不能再用字面量 {}
,必须得像下面这样:
let obj = new MyObject();
obj.name = "dby";
obj.age = 12;
obj.sex = 0;
obj.toString();
// "{\"name\":\"dby\",\"age\":12,\"sex\":0}"