news 2026/7/17 20:13:45

手撕小汇总

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
手撕小汇总

防抖

// 函数防抖的实现 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())); // 'set'

call

记得挂载函数,记得解构argument,记得解构args

Function.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 ctx=ctx??globalThis ctx= Object(ctx) const tempKey=Symbol('tempFn') ctx[tempKey]=this if(arguments[1]){ result = ctx[tempKey](...arguments[1]) }else{ result=ctx[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, 4,5] //或者直接用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); } }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/17 20:13:26

Windows 11 22H2版本选择与安装指南

1. Windows 11 22H2版本概述Windows 11 22H2&#xff08;2022年10月更新&#xff09;是微软操作系统的重要功能更新版本&#xff0c;内部版本号为22621。这个版本在21H2基础上进行了多项改进&#xff0c;包括开始菜单文件夹功能、任务栏拖放操作回归、文件资源管理器标签页等用…

作者头像 李华
网站建设 2026/7/17 20:13:19

爱芯派Pro开发板评测:72TOPS NPU与边缘计算实战

1. 爱芯派 Pro 开发板初印象 当我拆开快递包装时&#xff0c;这个黑色哑光外壳的开发板立刻吸引了我的目光。M4N-Dock 的尺寸比我想象中要小巧&#xff0c;约莫一个成年人的手掌大小&#xff0c;但拿在手里却有着沉甸甸的分量感。开发板正面最显眼的是那个带有散热鳍片的金属散…

作者头像 李华
网站建设 2026/7/17 20:10:38

DSP信号混频实验:创龙TL6748-TEB实验箱实战指南

1. 实验箱与实验背景介绍创龙教仪TL6748-TEB实验箱是面向高校DSP教学的经典设备&#xff0c;搭载TI C6000系列高性能DSP处理器。这个黑色金属箱体看似普通&#xff0c;却内置了丰富的信号处理资源&#xff1a;从多通道音频编解码器到可编程FPGA&#xff0c;从高速AD/DA到各种数…

作者头像 李华
网站建设 2026/7/17 20:09:10

AMD KV260视觉套件开箱与AI模型部署实战

1. KV260视觉入门套件开箱与基础配置KV260视觉入门套件是AMD&#xff08;原Xilinx&#xff09;推出的一款面向边缘AI应用的开发平台&#xff0c;搭载了Kria K26 SOM模块&#xff0c;内置可编程逻辑和双核ARM Cortex-A53处理器。这个套件特别适合需要低延迟、高性能的计算机视觉…

作者头像 李华
网站建设 2026/7/17 20:07:49

HarmonyOS掌上记账APP开发实践第28篇:自定义组件封装策略 — 从通用 Header 到业务组件的分层设计

自定义组件封装策略 — 从通用 Header 到业务组件的分层设计 一、引言 在大型应用中&#xff0c;合理的组件化设计是保证代码可维护性和复用性的基石。鸿蒙的 ArkTS 通过 ComponentV2 装饰器支持自定义组件&#xff0c;允许开发者将页面拆分为可复用的独立模块。MoneyTrack 项…

作者头像 李华