探索原生JS的力量:自定义实现类似于React的useState功能
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>相关文章:
探索原生JS的力量:自定义实现类似于React的useState功能
1.写在前面 本方案特别适合希望在历史遗留的原生JavaScript项目中实现简单轻量级数据驱动机制的开发者。无需引入任何框架或第三方库,即可按照此方法封装出类似于React中useState的功能,轻松为项目添加状态管理能力,既保持了项目的轻量性&am…...
探索 Shell 中的扩展通配符:从 Bash 到 Zsh
在 Unix 系统中,通配符(globbing)是 shell 的核心功能,用于快速匹配文件或目录。基础通配符(如 *、?、[])虽简单实用,但在复杂场景下往往力不从心。为此,许多现代 shell 提供了“扩…...
封装方法的辨析
equals //字符串 str1.equals(str2); //list的两个实现类 list1.equals(list2); //map的两个实现类 //比较所有的键值对是否相同 map1.equals(map2); //数组(包括string类型) //比较内容是否相同 Arrays.equals(array1, array2); contains 基本都有…...
[leetcode]判断质数
一.判断质数 1.1 什么是质数 质数(素数)就是只可以被自己和1整除的数叫做素数/质数 1.2判断方法 #include<bits/stdc.h> using namespace std; bool isPrime(int num) { if(num < 1) { return false;//a number less of …...
在Flutter中使用BottomNavigationBar和IndexedStack可以实现一个功能完整的底部导航栏
在Flutter中,使用BottomNavigationBar和IndexedStack可以实现一个功能完整的底部导航栏。BottomNavigationBar用于显示底部的导航按钮,而IndexedStack则用于管理页面的切换,确保每个页面的状态得以保留(即页面不会因为切换而重新构…...
HBuilder运行uni-app程序报错【Error: listen EACCES: permission denied 0.0.0.0:5173】
一、错误提示: 当使用HBuilder运行uni-app项目的时候提示了如下错误❌ 15:11:03.089 项目 project 开始编译 15:11:04.404 请注意运行模式下,因日志输出、sourcemap 以及未压缩源码等原因,性能和包体积,均不及发行模式。 15:11:04…...
聊透多线程编程-线程基础-3.C# Thread 如何从非UI线程直接更新UI元素
目录 1. 使用 Control.Invoke 或 Control.BeginInvoke(Windows Forms) 2. 使用 Dispatcher.Invoke 或 Dispatcher.BeginInvoke(WPF) 3. 使用 SynchronizationContext 桌面应用程序(如 Windows Forms 或 WPF…...
VMware Fusion Pro 13 for Mac虚拟机
VMware Fusion Pro 13 for Mac虚拟机 文章目录 VMware Fusion Pro 13 for Mac虚拟机一、介绍二、效果下载 一、介绍 VMware Fusion Pro for Mac,是一款mac虚拟机软件,跟Parallels Desktop一样,都可以让你的 Mac 同时运行一个或多个不同的操作…...
7.第二阶段x64游戏实战-string类
免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 本次游戏没法给 内容参考于:微尘网络安全 上一个内容:7.第二阶段x64游戏实战-分析人物属性 string类是字符串类,在计算机中…...
【debug莫名其妙跑飞了】
现象:就是在初始化汇编里跑飞了,也可能运行起来时钟不对 原因:调试器调试程序时会执行reset复位,reset没有正确执行。 细节决定成败,事出反常必有妖,忽略的小卡拉米最后能玩死你啊...
【Git 常用操作指令指南】
一、初始化与配置 1. 设置全局账户信息 git config --global user.name "用户名" # 设置全局用户名 git config --global user.email "邮箱" # 设置全局邮箱 --global 表示全局生效,若需针对单个仓库配置,可省略该参数 2.…...
基础知识补充篇:什么是DAPP前端连接中的provider
专栏:区块链入门到放弃查看目录-CSDN博客文章浏览阅读352次。为了方便查看将本专栏的所有内容列出目录,按照顺序查看即可。后续也会在此规划一下后续内容,因此如果遇到不能点击的,代表还没有更新。声明:文中所出观点大多数源于笔者多年开发经验所总结,如果你想要知道区块…...
openssl源码分析之加密模式(modes)
openssl实现分组加密模式(例如AES128-CBC的CBC部分)的模块名字叫做modes,源代码位于 https://gitee.com/gh_mirrors/openssl/tree/master/crypto/modes 博主又打不开github了TT,只能找个gitee镜像 头文件是modes.h。 该模块目前…...
【PVR】《Palm Vein Recognition and Large-scale Research based on Deep Learning》
邬晓毅. 基于深度学习的掌静脉识别及规模化研究[D]. 四川:电子科技大学,2024. 文章目录 1、背景2、相关工作3、创新点和贡献4、方法和实验4.1、知识介绍4.2、基于自适应损失函数的掌静脉识别算法研究4.3、退化图像的掌静脉识别鲁棒性提升研究4.4、掌静脉识别系统规模化 5、总结…...
ES6规范新特性总结
ES6新特性 var、let和const不存在变量提升暂时性死区不允许重复声明 解构赋值用途:交换变量的值从函数返回多个值提取JSON数据遍历map结构输入模块的制定方法 字符串的扩展codePointAt()String.fromCharCode()at()includes(),startsWith(),endsWith()repeat()padSta…...
PyQt学习记录
PyQt学习记录 要在界面上 创建一个控件,就需要在程序代码中 创建 这个 控件对应类 地一个 实例对象。 在Qt系统中,控件(widget)是 层层嵌套 的,除了最顶层的控件,其他的控件都有父控件。 几个函数 函数mo…...
嵌入式硬件篇---Uart和Zigbee
文章目录 前言一、UART(通用异步收发传输器)1. 基本概念2. 工作原理帧结构起始位数据位校验位停止位 异步通信波特率 3. 特点优点缺点 4. 典型应用 二、ZigBee1. 基本概念2. 技术细节工作频段2.4GHz868MHz 网络拓扑星型网络网状网络簇状网络 协议栈物理层…...
代码随想录算法训练营--打卡day8
一.反转字符串II 1.题目链接 541. 反转字符串 II - 力扣(LeetCode) 2.思路 循环分组定位:使用 for 循环,每2k为一组。i 每次增加 2k ,就相当于定位到下一组字符的起始位置。在每次循环中,确定当前组需要…...
Linux 学习笔记(5)路径知识详解:绝对路径、相对路径与特殊路径符(期末、期中复习必备)
前言 一、相对路径与绝对路径 1、概念阐述 2、实际示例 二、特殊路径符 1.特殊路径符介绍 2.应用场景 三、总结 四、结语 前言 在 Linux 系统的学习过程中,路径的概念至关重要,它是我们在文件系统中定位文件和目录的关键。今天,我们就…...
Trae + LangGPT 生成结构化 Prompt
Trae LangGPT 生成结构化 Prompt 0. 引言1. 安装 Trae2. 克隆 LangGPT3. Trae 和 LangGPT 联动4. 集成到 Dify 中 0. 引言 Github 上 LangGPT 这个项目,主要向我们介绍了写结构化Prompt的一些方法和示例,我们怎么直接使用这个项目,辅助我们…...
【ida】ida笔记
1 ida下载 IDA Pro 7.0 Windows 和 macOS 版本,包含全部 F5 插件 - 资源分享 - iOS 安全论坛 - 专注于研究 iOS 安全 - iOS Hacker 2 IDA基操 1 shiftF12 查看string信息 (通常可以看到重要的信息 ) 2 Alt T 查找带有目标字符串的函数 3 F5 查看C代码 4 Ctrl F…...
动态规划——两个数组的dp问题
目录 1. 最长公共子序列 2. 不相交的线 3. 不同的子序列 4. 通配符匹配 5. 正则表达式匹配 6. 交错字符串 7. 两个字符串的最小ASCII删除和 8. 最长重复子数组 1. 最长公共子序列 题目链接:1143. 最长公共子序列 - 力扣(LeetCode࿰…...
stream流Collectors.toMap(),key值重复问题
文章目录 一、问题二、问题示例三、原因四、解决方法4.1、方案一 一、问题 发现Collectors.toMap的一个坑,若key值重复的时候会抛异常。如: IllegalStateException: Duplicate key 男 二、问题示例 报错示例如下: import lombok.AllArgsC…...
机器学习 Day10 逻辑回归
1.简介 流程就是: 就是我们希望回归后激活函数给出的概率越是1和0. 2.API介绍 sklearn.linear_model.LogisticRegression 是 scikit-learn 库中用于实现逻辑回归算法的类,主要用于二分类或多分类问题。以下是对其重要参数的详细介绍: 2.1.…...
即时通讯软件BeeWorks,企业如何实现细粒度的权限控制?
BeeWorks作为一款专为企业设计的即时通讯平台,高度重视用户隐私安全,采取了多种措施来保障数据的保密性、完整性和可用性。 首先,BeeWorks采用私有化部署模式,企业可以将服务器架设在自己的网络环境中,所有通讯数据&a…...
Seq2Seq - Dataset 类
本节代码定义了一个 CMN 类,它继承自 PyTorch 的 Dataset 类,用于处理英文和中文的平行语料库。这个类的主要作用是将文本数据转换为模型可以处理的格式,并进行必要的填充操作,以确保所有序列的长度一致。 ⭐重写Dataset类是模型训…...
学习OpenCV C++版
OpenCV C 1 数据载入、显示与保存1.1 概念1.2 Mat 类构造与赋值1.3 Mat 类的赋值1.4 Mat 类支持的运算1.5 图像的读取与显示1.6 视频加载与摄像头调用1.7 数据保存 参考:《OpenCV4快速入门》作者冯 振 郭延宁 吕跃勇 1 数据载入、显示与保存 1.1 概念 Mat 类 : Ma…...
echarts图表相关
echarts图表相关 echarts官网折线图实际开发场景一: echarts官网 echarts官网 折线图 实际开发场景一: 只有一条折线,一半实线,一半虚线。 option {tooltip: {trigger: "axis",formatter: (params: any) > {const …...
idea自动部署jar包到服务器Alibaba Cloud Toolkit
安装插件:Alibaba Cloud Toolkit 配置服务器: 服务器配置: 项目启动Shell脚本命令: projectpd-otb.jar echo 根据项目名称查询对应的pid pid$(pgrep -f $project); echo $pid echo 杀掉对应的进程,如果pid不存在,则不执行 if [ …...
奥利司他
https://m.baidu.com/bh/m/detail/ar_9900965142893895938 奥利司他(四氢脂抑素)是一种众所周知的胰腺和胃脂肪酶不可逆抑制剂 生物活性:奥利司他(四氢脂抑素)是一种众所周知的胰腺和胃脂肪酶不可逆抑制剂。奥利司…...
