单例模式与懒加载:实现一个封装 localStorage 的 Storage 类与登录弹窗优化实践

165 阅读4分钟

引言

在现代前端开发中,设计模式和性能优化是构建高质量应用的重要基石。本文将围绕单例模式懒加载两大核心概念,详细讲解如何实现一个基于 localStorage 的单例 Storage 类,并结合实际场景优化登录弹窗的加载与使用方式。


一、单例模式简介

什么是单例模式?

单例模式(Singleton Pattern) 是一种常见的设计模式,其核心思想是:

确保一个类在整个程序中只能被实例化一次,并提供一个全局访问点来获取这个实例。

适用场景

  • 数据库连接池
  • 日志记录器(Logger)
  • 全局配置管理
  • 登录弹窗、全局状态管理等

JavaScript 中的实现方式

由于 JavaScript 并不支持类的私有构造函数,我们可以通过以下方式模拟单例:

  1. 闭包 + 模块模式
  2. ES6 类 + 静态属性
  3. Node.js 模块自动单例

二、实战:实现一个基于 localStorage 的单例 Storage 类

功能目标

  • 封装 localStorage
  • 提供 setItem(key, value) 和 getItem(key) 方法
  • 确保只有一个实例存在(单例)

实现代码

class Storage {
  static instance = null;

  constructor() {
    if (Storage.instance) {
      return Storage.instance;
    }
    Storage.instance = this;
  }

  // 设置值,自动序列化为 JSON
  setItem(key, value) {
    localStorage.setItem(key, JSON.stringify(value));
  }

  // 获取值,自动反序列化为 JS 对象
  getItem(key) {
    const value = localStorage.getItem(key);
    return value ? JSON.parse(value) : null;
  }
}

🧩 使用方式

const storage1 = new Storage();
const storage2 = new Storage();

storage1.setItem('username', '小明');
console.log(storage2.getItem('username')); // 输出: 小明

console.log(storage1 === storage2); // true

###设计解析

代码片段作用
static instance = null;保存唯一实例
constructor()构造函数中判断是否已存在实例
setItem()封装 localStorage.setItem 并自动序列化
getItem()封装 localStorage.getItem 并自动反序列化

三、结合实践:登录弹窗的优化(懒加载 + 单例)

优化目标

目标实现方式
不跳转页面,浮层显示使用 position: fixed 和 z-index 控制层级
用户点击时才加载资源使用懒加载,推迟 DOM 创建和样式加载
多次打开弹窗只创建一次使用单例模式,避免重复初始化
可以反复使用通过单例统一管理状态和行为

实现代码:单例 + 懒加载登录弹窗

class LoginModal {
  static instance = null;

  constructor() {
    if (LoginModal.instance) {
      return LoginModal.instance;
    }
    this.modal = null;
    LoginModal.instance = this;
  }

  // 懒加载初始化
  init() {
    if (this.modal) return;

    // 创建弹窗 DOM
    this.modal = document.createElement('div');
    this.modal.style.position = 'fixed';
    this.modal.style.top = '50%';
    this.modal.style.left = '50%';
    this.modal.style.transform = 'translate(-50%, -50%)';
    this.modal.style.width = '300px';
    this.modal.style.padding = '20px';
    this.modal.style.backgroundColor = '#fff';
    this.modal.style.boxShadow = '0 0 10px rgba(0,0,0,0.2)';
    this.modal.style.zIndex = '1000';
    this.modal.style.display = 'none';

    // 添加表单内容
    this.modal.innerHTML = `
      <h3>登录</h3>
      <input type="text" placeholder="用户名" id="login-username" />
      <input type="password" placeholder="密码" id="login-password" />
      <button id="login-btn">登录</button>
    `;

    // 添加到 body
    document.body.appendChild(this.modal);

    // 绑定事件
    document.getElementById('login-btn').addEventListener('click', () => {
      const username = document.getElementById('login-username').value;
      const password = document.getElementById('login-password').value;
      alert(`正在尝试登录:${username}`);
    });
  }

  // 显示弹窗
  show() {
    this.init(); // 第一次调用时初始化
    this.modal.style.display = 'block';
  }

  // 隐藏弹窗
  hide() {
    if (this.modal) {
      this.modal.style.display = 'none';
    }
  }
}

使用方式

<!-- 页面上添加一个按钮 -->
<button onclick="showLogin()">打开登录弹窗</button>

<script>
  function showLogin() {
    const modal = new LoginModal();
    modal.show();
  }
</script>

设计解析

代码片段作用
static instance = null;保存唯一实例
init() 方法只在第一次调用时创建 DOM
if (this.modal) return;如果已经创建过,就不再重复创建
show() 方法用户点击时才触发初始化和显示

四、懒加载的优势与性能优化

优势

优势说明
减少首屏加载时间不加载不必要的资源
节省内存不创建多余的 DOM 和监听器
提升用户体验页面更快加载,用户更早看到内容
更好地支持移动端移动设备网络慢,懒加载更友好

延伸:React 中的懒加载

const LazyComponent = React.lazy(() => import('./MyComponent'));

function App() {
  return (
    <React.Suspense fallback="加载中...">
      <LazyComponent />
    </React.Suspense>
  );
}

五、总结:单例 + 懒加载 = 高性能 + 易维护

技术作用
单例模式确保一个类只有一个实例,便于全局统一管理
懒加载推迟资源加载,提升性能
结合使用性能更好 + 体验更佳 + 结构更清晰

适用场景对比总结

功能实现方式设计思想
单例 使用orageES6 类 + 静态属性封装 + 单例
setItem / getItem封装 localStorage数据持久化
登录弹窗单例 + 懒加载性能优化 + UI 复用
弹窗显示/隐藏display 控制简洁交互
弹窗内容初始化第一次调用时才创建推迟加载资源

结语

掌握单例模式与懒加载,不仅能帮助你写出更清晰、高效的代码,还能在实际项目中显著提升用户体验和性能表现。无论是封装本地存储工具类,还是优化登录弹窗等 UI 组件,这两项技能都具有极高的实用价值。

如果你正在构建一个中大型前端应用,建议将这些设计思想融入到你的组件库或工具库中,让代码更具可维护性和可扩展性。