Storage 单例封装
用单例模式封装 localStorage 的 setItem 和 getItem 方法
问题
实现一个 Storage 类,要求:
- 该对象为单例,多次实例化返回同一个对象
- 封装 localStorage 的
setItem(key, value)和getItem(key)方法
解答
方式一:闭包实现
const Storage = (function() {
let instance = null;
function StorageClass() {
// 防止通过 new StorageClass() 直接调用
if (instance) {
return instance;
}
instance = this;
}
StorageClass.prototype.setItem = function(key, value) {
localStorage.setItem(key, JSON.stringify(value));
};
StorageClass.prototype.getItem = function(key) {
const value = localStorage.getItem(key);
return value ? JSON.parse(value) : null;
};
return StorageClass;
})();
// 测试
const s1 = new Storage();
const s2 = new Storage();
console.log(s1 === s2); // true
s1.setItem('name', 'Tom');
console.log(s2.getItem('name')); // 'Tom'
方式二:ES6 Class 静态方法
class Storage {
static instance = null;
constructor() {
// 如果已存在实例,直接返回
if (Storage.instance) {
return Storage.instance;
}
Storage.instance = this;
}
setItem(key, value) {
localStorage.setItem(key, JSON.stringify(value));
}
getItem(key) {
const value = localStorage.getItem(key);
return value ? JSON.parse(value) : null;
}
// 提供静态方法获取实例
static getInstance() {
if (!Storage.instance) {
Storage.instance = new Storage();
}
return Storage.instance;
}
}
// 测试
const s1 = Storage.getInstance();
const s2 = Storage.getInstance();
const s3 = new Storage();
console.log(s1 === s2); // true
console.log(s1 === s3); // true
方式三:Proxy 实现
class StorageBase {
setItem(key, value) {
localStorage.setItem(key, JSON.stringify(value));
}
getItem(key) {
const value = localStorage.getItem(key);
return value ? JSON.parse(value) : null;
}
}
// 用 Proxy 拦截构造函数
const Storage = new Proxy(StorageBase, {
instance: null,
construct(target, args) {
if (!this.instance) {
this.instance = new target(...args);
}
return this.instance;
}
});
// 测试
const s1 = new Storage();
const s2 = new Storage();
console.log(s1 === s2); // true
完整封装版本
class Storage {
static instance = null;
constructor() {
if (Storage.instance) {
return Storage.instance;
}
Storage.instance = this;
}
static getInstance() {
if (!Storage.instance) {
Storage.instance = new Storage();
}
return Storage.instance;
}
setItem(key, value) {
localStorage.setItem(key, JSON.stringify(value));
}
getItem(key) {
const value = localStorage.getItem(key);
try {
return JSON.parse(value);
} catch {
return value;
}
}
removeItem(key) {
localStorage.removeItem(key);
}
clear() {
localStorage.clear();
}
// 获取所有键
keys() {
return Object.keys(localStorage);
}
// 获取存储大小
size() {
return localStorage.length;
}
}
// 使用
const storage = Storage.getInstance();
storage.setItem('user', { name: 'Tom', age: 18 });
console.log(storage.getItem('user')); // { name: 'Tom', age: 18 }
关键点
- 单例核心:用静态属性保存实例,构造时判断是否已存在
- JSON 序列化:localStorage 只能存字符串,需要
JSON.stringify/parse处理 - 三种实现:闭包、Class 静态属性、Proxy,原理相同
- getInstance vs new:两种方式都应返回同一实例
- 错误处理:
getItem时需要 try-catch 处理非 JSON 字符串
目录