普陀区网站建百度搜索关键词怎么刷上去
1.写在前面
本方案特别适合希望在历史遗留的原生JavaScript项目中实现简单轻量级数据驱动机制的开发者。无需引入任何框架或第三方库,即可按照此方法封装出类似于React中useState
的功能,轻松为项目添加状态管理能力,既保持了项目的轻量性,又提升了开发效率
2.优势总结 ★ 了解
1. 轻量级响应式系统
-
无虚拟DOM:直接监听状态变化并更新真实DOM,避免虚拟DOM的diff计算开销
-
精准更新:只有订阅了状态变化的DOM元素会更新(相比React的组件级重渲染更精确)
2. 类React开发体验
-
提供
useState
+setState
的API设计,降低学习成本 -
支持函数式更新:
setState(prev => prev + 1)
3. 状态不可变性
-
自动深拷贝状态,避免意外修改
-
每次更新都生成新状态,便于实现时间旅行调试
4. 批量更新优化
-
batch()
可合并多次更新为单次渲染 -
避免频繁DOM操作导致的布局抖动
5. 多实例隔离
-
不同模块可以使用独立的状态实例,避免全局污染
3.单例模式 ★ 重要
单例模式效果展示
单例模式封装
/*** 单例模式状态管理* 整个应用共享同一个状态实例*/// ==================== 深拷贝工具 ====================
function deepClone(obj, hash = new WeakMap()) {if (obj == null) return obj;if (typeof obj !== 'object') return obj;const constructor = obj.constructor;const specialTypes = ['Date', 'RegExp', 'Map', 'Set'];if (specialTypes.includes(constructor.name)) {return new constructor(obj);}if (hash.has(obj)) return hash.get(obj);const clone = Array.isArray(obj) ? [] : Object.create(Object.getPrototypeOf(obj));hash.set(obj, clone);[...Object.getOwnPropertySymbols(obj), ...Object.keys(obj)].forEach(key => {clone[key] = deepClone(obj[key], hash);});return clone;
}// ==================== 核心实现 ====================
const subscribers = new Map();
let batchQueue = [];
let isBatching = false;function batchNotify(proxy) {const callbacks = subscribers.get(proxy);if (!callbacks) return;Promise.resolve().then(() => {callbacks.forEach(cb => {try {cb(proxy.value);} catch (e) {console.error('回调执行失败:', e);}});});
}export const useState = (initialState) => {if (typeof initialState === 'undefined') {throw new Error('初始状态不能为undefined');}const proxy = new Proxy({ value: deepClone(initialState) }, {set(target, key, value) {if (key !== 'value') return false;target[key] = deepClone(value);if (!isBatching) batchNotify(proxy);return true;}});return {get state() { return proxy.value; },setState: (updater) => {if (isBatching) {batchQueue.push({ proxy, updater });} else {proxy.value = typeof updater === 'function' ? updater(proxy.value) : updater;}},subscribe: (callback) => {if (typeof callback !== 'function') {throw new Error('回调必须是函数');}if (!subscribers.has(proxy)) {subscribers.set(proxy, new Set());}subscribers.get(proxy).add(callback);return () => {subscribers.get(proxy)?.delete(callback);};}};
};export const batch = (callback) => {if (isBatching) return callback();isBatching = true;batchQueue = [];try {callback();const updatesByProxy = new Map();batchQueue.forEach(({ proxy, updater }) => {if (!updatesByProxy.has(proxy)) {updatesByProxy.set(proxy, []);}updatesByProxy.get(proxy).push(updater);});updatesByProxy.forEach((updaters, proxy) => {let state = proxy.value;updaters.forEach(updater => {state = typeof updater === 'function' ? updater(state) : updater;state = deepClone(state);});proxy.value = state;batchNotify(proxy);});} finally {isBatching = false;batchQueue = [];}
};
单例模式HTML测试
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>单例模式测试</title><script type="module">import { useState, batch } from './singleton-state.js';const counter = useState(0);counter.subscribe(count => {document.getElementById('count').textContent = count;console.log('当前计数:', count);});// 普通更新document.getElementById('increment').addEventListener('click', () => {counter.setState(c => c + 1);});// 批量更新document.getElementById('increment-5').addEventListener('click', () => {batch(() => {counter.setState(c => c + 1);counter.setState(c => c + 1);counter.setState(c => c + 1);counter.setState(c => c + 1);counter.setState(c => c + 1);});});</script>
</head>
<body>
<h1>单例模式测试</h1>
<div>计数: <span id="count">0</span></div>
<button id="increment">+1</button>
<button id="increment-5">+5 (批量)</button>
</body>
</html>
4.多例模式 ★ 重要·推荐
双例模式效果展示
双例模式封装
/*** 多例模式状态管理工具* 允许创建多个独立的状态管理实例,每个实例拥有独立的状态和订阅系统* * 主要特点:* 1. 可创建多个隔离的状态管理实例* 2. 每个实例拥有独立的useState和batch方法* 3. 完整的状态不可变性保证* 4. 支持批量更新优化性能* * 使用方式:* const store = createStateStore();* const counter = store.useState(0);* * counter.subscribe(state => console.log(state));* counter.setState(prev => prev + 1);* store.batch(() => { ... });*/// ==================== 深拷贝工具函数 ====================/*** 高性能深拷贝函数* @param {any} obj - 需要拷贝的对象* @param {WeakMap} [hash=new WeakMap()] - 用于存储已拷贝对象的WeakMap(防止循环引用)* @returns {any} 深拷贝后的对象* * 实现特点:* 1. 处理基本数据类型:直接返回* 2. 处理循环引用:使用WeakMap缓存已拷贝对象* 3. 保留特殊对象类型:Date、RegExp等* 4. 原型链继承:保持原型链关系* 5. 性能优化:使用Object.keys+Symbol属性遍历*/
function deepClone(obj, hash = new WeakMap()) {// 处理null和undefinedif (obj == null) return obj;// 处理基本数据类型(string, number, boolean, symbol, bigint)if (typeof obj !== 'object') return obj;// 处理特殊对象类型const constructor = obj.constructor;const specialTypes = ['Date', 'RegExp', 'Map', 'Set', 'WeakMap', 'WeakSet'];if (specialTypes.includes(constructor.name)) {return new constructor(obj);}// 检查循环引用if (hash.has(obj)) return hash.get(obj);// 根据对象类型创建空对象或数组const clone = Array.isArray(obj) ? [] : Object.create(Object.getPrototypeOf(obj));// 缓存当前对象,防止循环引用hash.set(obj, clone);// 拷贝Symbol类型属性const symKeys = Object.getOwnPropertySymbols(obj);if (symKeys.length > 0) {symKeys.forEach(symKey => {clone[symKey] = deepClone(obj[symKey], hash);});}// 拷贝普通属性Object.keys(obj).forEach(key => {clone[key] = deepClone(obj[key], hash);});return clone;
}// ==================== 状态管理工厂函数 ====================/*** 创建新的状态管理实例* @returns {Object} 包含useState和batch方法的对象* * 每个实例包含:* 1. 独立的订阅者系统* 2. 独立的批量更新队列* 3. 独立的状态树*/
export function createStateStore() {/*** 订阅者集合* Map结构:* key: 状态代理对象(Proxy)* value: 该状态的订阅者回调集合(Set)*/const subscribers = new Map();/*** 批量更新队列* 数组结构,每个元素包含:* - proxy: 状态代理对象* - updater: 更新函数或值*/let batchQueue = [];/*** 批量更新标志* @type {boolean}*/let isBatching = false;// ==================== 内部工具方法 ====================/*** 通知订阅者状态变更* @param {Proxy} proxy - 状态代理对象* * 实现特点:* 1. 使用微任务(Promise)异步执行通知* 2. 错误处理避免影响其他订阅者* 3. 自动清理无效订阅*/function batchNotify(proxy) {// 获取当前状态的所有订阅者const callbacks = subscribers.get(proxy);if (!callbacks || callbacks.size === 0) return;// 使用微任务异步执行通知Promise.resolve().then(() => {// 获取当前状态值const state = proxy.value;// 遍历执行所有订阅回调callbacks.forEach(callback => {try {callback(state);} catch (error) {console.error('[状态通知错误] 订阅回调执行失败:', error);}});});}// ==================== 公开API ====================/*** 创建响应式状态* @param {any} initialState - 初始状态* @returns {Object} 包含state、setState和subscribe方法的对象* * @throws {Error} 当initialState为undefined时抛出错误*/function useState(initialState) {// 参数校验if (typeof initialState === 'undefined') {throw new Error('useState: 初始状态不能为undefined');}// 创建响应式代理对象const proxy = new Proxy({ value: deepClone(initialState) },{/*** 代理set陷阱* @param {Object} target - 目标对象* @param {string} key - 属性名* @param {any} value - 新值* @returns {boolean} 是否设置成功*/set(target, key, value) {// 只处理value属性的变更if (key !== 'value') return false;// 深拷贝新值,确保状态不可变target[key] = deepClone(value);// 非批量模式下立即通知订阅者if (!isBatching) {batchNotify(proxy);}return true;}});/*** 订阅状态变更* @param {Function} callback - 状态变更回调函数* @returns {Function} 取消订阅的函数* * @throws {Error} 当callback不是函数时抛出错误*/function subscribe(callback) {// 参数校验if (typeof callback !== 'function') {throw new Error('subscribe: 回调必须是函数');}// 初始化该状态的订阅者集合if (!subscribers.has(proxy)) {subscribers.set(proxy, new Set());}// 添加订阅者const callbacks = subscribers.get(proxy);callbacks.add(callback);// 返回取消订阅函数return function unsubscribe() {callbacks.delete(callback);// 清理空订阅集合if (callbacks.size === 0) {subscribers.delete(proxy);}};}/*** 更新状态* @param {Function|any} updater - 更新函数或新状态值* * 更新规则:* 1. 如果是函数:updater(prevState) => newState* 2. 如果是值:直接替换状态*/function setState(updater) {if (isBatching) {// 批量模式下将更新操作加入队列batchQueue.push({proxy,updater});} else {// 直接更新模式proxy.value = typeof updater === 'function'? updater(proxy.value): updater;}}// 返回状态访问接口return {/*** 获取当前状态值* @returns {any} 当前状态*/get state() {return proxy.value;},setState,subscribe};}/*** 批量更新状态* @param {Function} callback - 包含多个状态更新的回调函数* * 实现特点:* 1. 合并多个setState调用为一次更新* 2. 自动处理状态依赖关系* 3. 最终只触发一次订阅通知*/function batch(callback) {// 如果已经在批量模式中,直接执行回调if (isBatching) {callback();return;}// 进入批量模式isBatching = true;batchQueue = [];try {// 执行用户回调,收集所有setState操作callback();// 按状态代理分组更新操作const updatesByProxy = new Map();batchQueue.forEach(({ proxy, updater }) => {if (!updatesByProxy.has(proxy)) {updatesByProxy.set(proxy, []);}updatesByProxy.get(proxy).push(updater);});// 处理每个状态代理的更新updatesByProxy.forEach((updaters, proxy) => {let currentState = proxy.value;// 按顺序应用所有更新器updaters.forEach(updater => {currentState = typeof updater === 'function'? updater(currentState): updater;// 确保每次更新都是不可变的currentState = deepClone(currentState);});// 最终更新状态值proxy.value = currentState;// 通知该状态的订阅者batchNotify(proxy);});} finally {// 确保无论是否出错都退出批量模式isBatching = false;batchQueue = [];}}// 返回实例方法return { useState, batch };
}// ==================== 可选默认实例 ====================/*** 默认导出的状态管理实例* 为方便使用,同时提供创建新实例和默认实例两种方式*/
const defaultStore = createStateStore();
export const { useState: defaultUseState, batch: defaultBatch } = defaultStore;
双例模式HTML测试
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>多例模式状态管理测试</title><style>body {font-family: Arial, sans-serif;max-width: 600px;margin: 0 auto;padding: 20px;}.counter {margin: 20px 0;padding: 15px;border: 1px solid #ddd;border-radius: 5px;}button {padding: 8px 16px;margin-right: 10px;cursor: pointer;}</style>
</head>
<body><h1>多例模式状态管理测试</h1><div class="counter"><h2>独立计数器1</h2><div>当前值: <span id="counter1-value">0</span></div><button id="counter1-increment">增加</button><button id="counter1-batch">批量增加(+3)</button></div><div class="counter"><h2>独立计数器2</h2><div>当前值: <span id="counter2-value">100</span></div><button id="counter2-increment">增加</button></div><script type="module">// 从模块导入创建方法import { createStateStore } from './multi-state.js';// 创建两个完全独立的状态管理实例const store1 = createStateStore();const store2 = createStateStore();// 实例1:计数器1const counter1 = store1.useState(0);counter1.subscribe(state => {document.getElementById('counter1-value').textContent = state;console.log('计数器1更新:', state);});document.getElementById('counter1-increment').addEventListener('click', () => {counter1.setState(prev => prev + 1);});document.getElementById('counter1-batch').addEventListener('click', () => {store1.batch(() => {counter1.setState(prev => prev + 1);counter1.setState(prev => prev + 1);counter1.setState(prev => prev + 1);});});// 实例2:计数器2 (完全独立)const counter2 = store2.useState(100);counter2.subscribe(state => {document.getElementById('counter2-value').textContent = state;console.log('计数器2更新:', state);});document.getElementById('counter2-increment').addEventListener('click', () => {counter2.setState(prev => prev + 10);});// 暴露到全局方便测试window.stores = { store1, store2, counter1, counter2 };</script><div style="margin-top: 30px; color: #666;"><h3>测试说明:</h3><p>1. 两个计数器使用完全独立的状态管理实例</p><p>2. 打开控制台可以查看状态变化日志</p><p>3. 在控制台输入 <code>stores</code> 可以访问状态实例</p></div>
</body>
</html>
5.单例模式和双例模式的区别 ★ 了解
-
单例模式:
-
全局共享一个状态树
-
直接导出
useState
和batch
-
适合中小型应用
-
-
多例模式:
-
通过
createStateStore()
创建独立实例 -
每个实例有自己的状态和订阅系统
-
适合大型应用或需要隔离状态的场景
-
6.兼容性分析 ★ 了解
1. 支持的浏览器
特性 | 最低支持版本 | 覆盖率 |
---|---|---|
Proxy | Chrome 49+ | ~98% |
Firefox 18+ | ||
Edge 12+ | ||
Safari 10+ | ||
WeakMap | IE 11+ | ~99% |
Promise (微任务) | ES6+ | ~98% |
2. 不兼容场景
-
IE 11及以下:不支持Proxy(可用
Object.defineProperty
降级) -
老旧移动浏览器:部分Android 4.x设备不支持ES6
3. Polyfill方案
// 在入口文件添加以下polyfill
import 'core-js/stable'; // 提供Promise/WeakMap等
import 'proxy-polyfill'; // 提供Proxy的简单实现
7.全代码测试页 ★ 了解·测试
<!DOCTYPE html>
<html lang="zh-CN">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>高性能响应式状态管理</title><style>body {font-family: Arial, sans-serif;max-width: 800px;margin: 0 auto;padding: 20px;line-height: 1.6;}button {padding: 8px 16px;margin: 5px;cursor: pointer;background-color: #4CAF50;color: white;border: none;border-radius: 4px;}button:hover {background-color: #45a049;}.container {margin: 20px 0;padding: 15px;border: 1px solid #ddd;border-radius: 5px;}pre {background-color: #f5f5f5;padding: 10px;border-radius: 4px;overflow-x: auto;}.perf-info {color: #666;font-size: 0.9em;margin-top: 5px;}</style>
</head>
<body>
<h1>高性能响应式状态管理</h1><!-- 计数器容器 -->
<div class="container"><h2>性能计数器</h2><div>当前值: <span id="counter-value">0</span></div><div class="perf-info" id="counter-perf"></div><button id="increment">增加 (+1)</button><button id="increment-100">快速增加100次</button><button id="increment-1000">压力测试1000次</button>
</div><!-- 用户信息容器 -->
<div class="container"><h2>用户信息</h2><pre id="user-info"></pre><div class="perf-info" id="user-perf"></div><button id="update-user">更新用户信息</button>
</div><!-- 待办事项容器 -->
<div class="container"><h2>待办事项</h2><ul id="todo-list"></ul><input type="text" id="new-todo" placeholder="输入新事项"><button id="add-todo">添加</button><div class="perf-info" id="todo-perf"></div>
</div><script>/*** 高性能深拷贝函数* 特点:* 1. 处理循环引用* 2. 保留特殊对象类型(Date, RegExp等)* 3. 惰性拷贝(按需拷贝)* @param {any} obj - 需要拷贝的对象* @param {WeakMap} hash - 用于存储已拷贝对象的WeakMap(防止循环引用)* @return {any} 深拷贝后的对象*/function deepClone(obj, hash = new WeakMap()) {// 基本类型直接返回if (obj === null || typeof obj !== 'object') return obj;// 处理循环引用if (hash.has(obj)) return hash.get(obj);// 处理特殊对象const constructor = obj.constructor;if (/^(Date|RegExp|Map|Set)$/i.test(constructor.name)) {return new constructor(obj);}// 初始化克隆对象const clone = Array.isArray(obj) ? [] : Object.create(Object.getPrototypeOf(obj));hash.set(obj, clone);// 使用Object.keys+forEach比for-in性能更好Object.keys(obj).forEach(key => {clone[key] = deepClone(obj[key], hash);});return clone;}/*** 创建高性能状态管理Store* @return {Object} 包含useState和batch方法的对象*/function createStore() {const subscribers = new Map(); // 存储订阅者回调函数let batchQueue = []; // 批量更新队列let isBatching = false; // 是否处于批量更新模式/*** 批量执行回调(使用微任务节流)* @param {Proxy} proxy - 状态代理对象*/function batchNotify(proxy) {const callbacks = subscribers.get(proxy);if (!callbacks) return;// 使用微任务确保在UI更新前处理所有状态变更Promise.resolve().then(() => {const state = proxy.value;callbacks.forEach(callback => {try {callback(state);} catch (e) {console.error('订阅回调出错:', e);}});});}/*** 创建响应式状态* @param {any} initialState - 初始状态* @return {Object} 包含state、setState和subscribe方法的对象*/function useState(initialState) {// 验证初始状态if (typeof initialState === 'undefined') {throw new Error('Initial state cannot be undefined');}// 创建响应式代理const proxy = new Proxy({ value: deepClone(initialState) }, {set(target, key, value) {if (key !== 'value') return false;// 深拷贝新值target[key] = deepClone(value);// 非批量模式下立即通知if (!isBatching) {batchNotify(proxy);}return true;}});/*** 订阅状态变化* @param {Function} callback - 状态变化时的回调函数* @return {Function} 取消订阅的函数*/function subscribe(callback) {if (typeof callback !== 'function') {throw new Error('订阅回调必须是一个函数');}if (!subscribers.has(proxy)) {subscribers.set(proxy, new Set());}const callbacks = subscribers.get(proxy);callbacks.add(callback);// 返回取消订阅函数return () => {callbacks.delete(callback);if (callbacks.size === 0) {subscribers.delete(proxy);}};}/*** 更新状态* @param {Function|any} updater - 更新函数或新状态*/function setState(updater) {if (isBatching) {// 批量模式下将更新器和代理存入队列batchQueue.push({proxy,updater});} else {// 直接更新proxy.value = typeof updater === 'function'? updater(proxy.value): updater;}}return {get state() { return proxy.value; }, // 获取当前状态setState, // 更新状态方法subscribe // 订阅状态变化方法};}/*** 批量更新* @param {Function} callback - 包含多个状态更新的回调函数*/function batch(callback) {isBatching = true;batchQueue = []; // 清空队列try {callback(); // 执行回调,收集所有setState调用// 将更新按对应的状态代理分组const updatesByProxy = new Map();batchQueue.forEach(({ proxy, updater }) => {if (!updatesByProxy.has(proxy)) {updatesByProxy.set(proxy, []);}updatesByProxy.get(proxy).push(updater);});// 处理每个代理的更新队列updatesByProxy.forEach((updaters, proxy) => {let currentState = proxy.value;// 按顺序应用所有更新器函数updaters.forEach(updater => {currentState = typeof updater === 'function'? updater(currentState) // 基于当前状态计算新值: updater;currentState = deepClone(currentState); // 深拷贝新状态});// 一次性更新代理的值proxy.value = currentState;// 手动触发通知batchNotify(proxy);});} finally {isBatching = false;batchQueue = []; // 清空队列}}return { useState, batch };}// ==================== 使用示例 ====================const { useState, batch } = createStore();/*** 性能监控工具* @param {string} name - 监控器名称* @return {Object} 包含record和updateUI方法的对象*/function createPerfMonitor(name) {let lastTime = performance.now();let count = 0;let totalTime = 0;return {/*** 记录性能数据* @return {Object} 包含duration、avg和count的性能数据*/record() {const now = performance.now();const duration = now - lastTime;lastTime = now;count++;totalTime += duration;return {duration: duration.toFixed(2),avg: (totalTime / count).toFixed(2),count};},/*** 更新UI显示性能数据* @param {string} elementId - 显示性能数据的元素ID*/updateUI(elementId) {const perf = this.record();document.getElementById(elementId).textContent =`最近更新: ${perf.duration}ms | 平均: ${perf.avg}ms | 更新次数: ${perf.count}`;}};}// 1. 计数器状态const counter = useState(0);const counterPerf = createPerfMonitor('counter');// 订阅计数器状态变化counter.subscribe(count => {document.getElementById('counter-value').textContent = count;counterPerf.updateUI('counter-perf');});// 2. 用户信息状态const user = useState({name: '张三',age: 25,address: {city: '北京',street: '朝阳区'},createdAt: new Date()});const userPerf = createPerfMonitor('user');// 订阅用户信息状态变化user.subscribe(user => {document.getElementById('user-info').textContent = JSON.stringify(user, null, 2);userPerf.updateUI('user-perf');});// 3. 待办事项状态const todos = useState([]);const todoPerf = createPerfMonitor('todo');// 订阅待办事项状态变化todos.subscribe(todos => {const listElement = document.getElementById('todo-list');listElement.innerHTML = '';todos.forEach((todo, index) => {const li = document.createElement('li');li.textContent = `${index + 1}. ${todo.text}`;if (todo.completed) {li.style.textDecoration = 'line-through';li.style.color = '#888';}// 添加完成/取消按钮const completeButton = document.createElement('button');completeButton.textContent = todo.completed ? '取消' : '完成';completeButton.style.marginLeft = '10px';completeButton.onclick = () => {todos.setState(prev => {const newTodos = [...prev];newTodos[index] = {...newTodos[index],completed: !newTodos[index].completed};return newTodos;});};li.appendChild(completeButton);listElement.appendChild(li);});todoPerf.updateUI('todo-perf');});// ==================== 事件绑定 ====================// 计数器操作document.getElementById('increment').addEventListener('click', () => {counter.setState(c => c + 1);});document.getElementById('increment-100').addEventListener('click', () => {batch(() => {for (let i = 0; i < 100; i++) {counter.setState(c => c + 1);}});});document.getElementById('increment-1000').addEventListener('click', () => {batch(() => {for (let i = 0; i < 1000; i++) {counter.setState(c => c + 1);}});});// 用户信息操作document.getElementById('update-user').addEventListener('click', () => {user.setState(prev => ({...prev,age: prev.age + 1,address: {...prev.address,street: `朝阳区${Math.floor(Math.random() * 100)}号`},updatedAt: new Date()}));});// 待办事项操作document.getElementById('add-todo').addEventListener('click', () => {const input = document.getElementById('new-todo');const text = input.value.trim();if (text) {todos.setState(prev => [...prev,{ text, completed: false }]);input.value = '';}});// 初始化输入框回车事件document.getElementById('new-todo').addEventListener('keypress', (e) => {if (e.key === 'Enter') {document.getElementById('add-todo').click();}});
</script>
</body>
</html>