手撕小汇总 防抖// 函数防抖的实现 function debounce(fn, wait) { let timer null; return function() { let context this, args arguments; // 如果此时存在定时器的话则取消之前的定时器重新记时 if (timer) { clearTimeout(timer); timer null; } // 设置定时器使事件间隔指定事件后执行 timer setTimeout(() { fn.apply(context, args); }, wait); }; }节流时间戳版首段执行无尾调用// 函数节流的实现; function throttle(fn, delay) { let curTime Date.now(); return function() { let context this, args arguments, nowTime Date.now(); // 如果两次时间间隔超过了指定时间则执行函数。 if (nowTime - curTime delay) { curTime Date.now(); fn.apply(context, args); } }; }定时器版首段延迟有尾调用function throttle(fn, delay) { let timer null; return function () { const context this; const args arguments; if (!timer) { timer setTimeout(() { fn.apply(context, args); timer null; }, delay); } }; }融合版首尾调用都有function throttle(fn, delay) { // 上一次执行的时间戳 let lastTime Date.now(); // 兜底定时器标识 let timer null; return function () { const context this; const args arguments; // 当前触发时间 const now Date.now(); // 距离下一次允许执行还剩多久 const remain delay - (now - lastTime); // 场景1剩余时间 0达到间隔可以立即执行 if (remain 0) { // 如果存在等待中的兜底定时器直接清除防止重复执行 if (timer) { clearTimeout(timer); timer null; } lastTime now; fn.apply(context, args); } // 场景2时间还不足且当前没有等待的定时器则创建兜底任务 else if (!timer) { timer setTimeout(() { lastTime Date.now(); timer null; fn.apply(context, args); }, remain); } } }类型判断function getType(value) { // 单独处理两大特殊基础类型 if (value null) return null if (value undefined) return undefined // 统一调用toString const rawType Object.prototype.toString.call(value) // 截取 [object Xxx] 中间字符串 return rawType.slice(8, -1).toLowerCase() } console.log(getType(null)); // null console.log(getType(undefined)); // undefined console.log(getType(123)); // number console.log(getType(123n)); // bigint console.log(getType(aaa)); // string console.log(getType(true)); // boolean console.log(getType(Symbol())); // symbol console.log(getType([])); // array console.log(getType({})); // object console.log(getType(function(){})); // function console.log(getType(new Date())); // date console.log(getType(/\w/)); // regexp console.log(getType(new Map())); // map console.log(getType(new Set())); // setcall记得挂载函数记得解构argument记得解构argsFunction.prototype.myCall function(context) { // 1. 校验调用者必须是函数 if (typeof this ! function) { throw new TypeError(this is not a function); } // 2. 仅null/undefined替换为全局其余值原样保留 context context ?? globalThis; // 3.原始值自动装箱 context Object(context); // 4. 创建唯一临时key防止属性覆盖冲突 const tempKey Symbol(tempFunc); // 5. 挂载函数(此处this是调用call的函数) context[tempKey] this; // 6. 截取参数执行 const args [...arguments].slice(1); const result context[tempKey](...args); // 7. 删除临时方法 delete context[tempKey]; return result; };apply记得解构arguments没传参记得加function apply(ctx) { if (typeof this ! function) { throw new TypeError(type error) } let result null ctxctx??globalThis ctx Object(ctx) const tempKeySymbol(tempFn) ctx[tempKey]this if(arguments[1]){ result ctx[tempKey](...arguments[1]) }else{ resultctx[tempKey]() } delete ctx[tempKey] return result }bind解构argument参数使用concat合并解构的argument// bind 函数实现 Function.prototype.myBind function(context) { // 判断调用对象是否为函数 if (typeof this ! function) { throw new TypeError(Error); } // 获取参数 let args [...arguments].slice(1), fn this; return function Fn() { // 根据调用方式传入不同绑定值 return fn.apply( this instanceof Fn ? this : context, args.concat(...arguments) ); }; };函数柯里化function curry(fn) { // fn.length 获取函数预期形参数量 const len fn.length return function curried(...args) { // 收集参数 需要参数 → 执行 if(args.length len) { return fn(...args) } // 参数不够继续返回新函数收集 return function(...newArgs) { return curried(...args, ...newArgs) } } }浅拷贝// 浅拷贝的实现; function shallowCopy(object) { // 只拷贝对象 if (!object || typeof object ! object) return; // 根据 object 的类型判断是新建一个数组还是对象 let newObject Array.isArray(object) ? [] : {}; // 遍历 object并且判断是 object 的属性才拷贝 for (let key in object) { if (object.hasOwnProperty(key)) { newObject[key] object[key]; } } return newObject; }深拷贝// 深拷贝的实现 function deepCopy(object) { if (!object || typeof object ! object) return; let newObject Array.isArray(object) ? [] : {}; for (let key in object) { if (object.hasOwnProperty(key)) { newObject[key] typeof object[key] object ? deepCopy(object[key]) : object[key]; } } return newObject; }数组求和可多维求和const sum arr.flat(Infinity).reduce((s, v) s v, 0)数组扁平化let arr [1, [2, [3, 4]]]; function flatten(arr) { while (arr.some(item Array.isArray(item))) { arr [].concat(...arr); } return arr; } console.log(flatten(arr)); // [1, 2, 3, 45] //或者直接用flat用Promise实现图片的异步加载let imageAsync(url){ return new Promise((resolve,reject){ let img new Image(); img.src url; img.οnlοad(){ console.log(图片请求成功此处进行通用操作); resolve(image); } img.οnerrοr(err){ console.log(失败此处进行失败的通用操作); reject(err); } }) } imageAsync(url).then((){ console.log(加载成功); }).catch((error){ console.log(加载失败); })实现发布-订阅模式class EventBus { constructor() { // 存储 { 事件名: [回调函数列表] } this.events Object.create(null); } // 订阅on(事件名, 回调) on(eventName, callback) { if (!this.events[eventName]) { this.events[eventName] []; } this.events[eventName].push(callback); } // 发布/触发emit(事件名, 参数...) emit(eventName, ...args) { const cbs this.events[eventName]; if (!cbs) return; // 循环执行所有订阅回调传入参数 cbs.forEach(fn fn(...args)); } // 取消订阅off(事件名, 指定回调) off(eventName, callback) { const cbs this.events[eventName]; if (!cbs) return; this.events[eventName] cbs.filter(item item ! callback); } // 一次性订阅once触发后自动解绑 once(eventName, callback) { const wrapper (...args) { callback(...args); this.off(eventName, wrapper); }; this.on(eventName, wrapper); } }

相关新闻

最新新闻

LLM与RAG技术提升工单处理效率的实践

LLM与RAG技术提升工单处理效率的实践

1. 项目背景与核心价值在客户服务领域,工单处理效率直接影响企业运营成本和用户体验。传统工单系统面临三个典型痛点:人工响应速度慢(平均处理时间超过4小时)、解决方案标准化程度低(依赖客服个人经验)、历…

2026/7/17 21:14:13
让向量听懂孤独:我是如何用 Elastic Agent Builder 构建一个情绪疗愈 agent 的

让向量听懂孤独:我是如何用 Elastic Agent Builder 构建一个情绪疗愈 agent 的

作者:翟献帅 | Elasticsearch Agent Builder Hackathon 北京 本内容遵循 CC 4.0 BY-SA 版权协议 深夜的聊天框里,有人打下这样一句话: “最近觉得,再热闹也和谁都隔着一层,提不起劲。” 这句话里,没有“孤…

2026/7/17 21:14:13
SAP UI5 中如何实现类似 Angular SimpleChanges 的属性变更感知

SAP UI5 中如何实现类似 Angular SimpleChanges 的属性变更感知

我们今天正在做的事情很具体,把 Angular 组件体系里的一个概念,准确地映射到 SAP UI5,而不是只根据名字寻找一个看起来相似的类。把问题直接落到结论上,SAP UI5 没有一个公开、稳定、可供应用代码直接使用,并且与 @angular/core 中 SimpleChanges 完全一一对应的类型,也没…

2026/7/17 21:14:13
芒果派MQ Quad开发板刷机与RISC-V嵌入式开发指南

芒果派MQ Quad开发板刷机与RISC-V嵌入式开发指南

1. 芒果派MQ Quad开发板初识芒果派MQ Quad是一款基于全志D1-H主控的RISC-V架构开发板,尺寸仅为65x30mm,却集成了丰富的外设接口和功能模块。作为芒果派系列的最新成员,它延续了该系列"小而美"的设计理念,在紧凑的板型上…

2026/7/17 21:14:13
跨平台快照测试实战:解决Windows、Linux、macOS环境差异

跨平台快照测试实战:解决Windows、Linux、macOS环境差异

1. 项目概述:为什么我们需要跨平台的快照测试在软件开发,特别是前端和UI组件的开发流程里,快照测试(Snapshot Testing)已经成为保障视觉一致性和防止回归的黄金标准。简单来说,它就像给你的代码界面拍一张“…

2026/7/17 21:14:13
STM32开发板实现音乐播放器:LVGL界面与VS1053B音频解码

STM32开发板实现音乐播放器:LVGL界面与VS1053B音频解码

1. 项目背景与开发板选型 正点原子STM32战舰V4开发板作为嵌入式开发的经典平台,其硬件配置非常适合多媒体类项目的实现。这款开发板搭载STM32F103ZET6芯片,拥有512KB Flash和64KB RAM,外设资源丰富,包括FSMC接口(可直接…

2026/7/17 21:09:13

月新闻