当前位置: 首页 > news >正文

前端手写题(一)

目录

一、深拷贝

 二、防抖

三、节流

四、函数柯里化

 五、instanceof

六、typeof


一、深拷贝

实现步骤:

  1. 检查是否为基本类型,如果是则直接返回
  2. 检测是否为循环引用,如果是则返回缓存对象
  3. 处理特殊对象类型
  4. 创建新对象/数组,同时保留原型链
  5. 缓存当前对象,防止循环引用
  6. 递归拷贝所有属性
  7. 返回克隆结果
function deepClone(target, map = new WeakMap()) {// 基本类型直接返回if (target === null || typeof target !== 'object') return target;// 处理循环引用if (map.has(target)) return map.get(target);// 处理特殊对象类型if (target instanceof Date) return new Date(target);if (target instanceof RegExp) return new RegExp(target);if (target instanceof Map) return new Map(Array.from(target, ([k, v]) => [deepClone(k, map), deepClone(v, map)]));if (target instanceof Set) return new Set(Array.from(target, v => deepClone(v, map)));// 创建新对象或数组(保持原型链)const cloneTarget = Array.isArray(target)? []: Object.create(Object.getPrototypeOf(target));// 记录拷贝关系(放在递归前,避免循环引用无限递归)map.set(target, cloneTarget);// 递归拷贝所有属性(包括Symbol)Reflect.ownKeys(target).forEach(key => {cloneTarget[key] = deepClone(target[key], map);});return cloneTarget;
}
  • 第二个参数map:记录已克隆对象,防止循环引用(对象嵌套引用自身)导致无限递归。
  •  WeakMap:键是​​弱引用​​,键类型必须是对象,键无引用时键值对会被自动删除,且不可迭代。特点:自动内存管理,更安全,适合临时关联数据。
  • Reflect.ownKeys():返回一个由目标对象自身的所有键组成的数组,无论它们是否可枚举。
// 测试循环引用和特殊对象
const original = {date: new Date(),regExp: /test/g,map: new Map([['key', 'value']]),set: new Set([1, 2, 3]),nested: { a: 1 }
};
original.self = original;const cloned = deepClone(original);// 测试结果
console.log('深拷贝测试:');
console.log('日期对象:', cloned.date instanceof Date); // true
console.log('正则对象:', cloned.regExp instanceof RegExp); // true
console.log('Map对象:', cloned.map instanceof Map); // true
console.log('Set对象:', cloned.set instanceof Set); // true
console.log('循环引用:', cloned.self === cloned); // true
console.log('嵌套对象:', cloned.nested.a === 1); // true

 二、防抖

防抖:在事件被频繁触发时,只有最后一次操作会被执行,中间的触发会被忽略

当前实现模式:延迟执行,连续触发事件时,只在最后一次触发后的 delay 毫秒后执行一次

function debounce(fn, delay) {let timer = null;return function(...args) {const context = this;clearTimeout(timer);timer = setTimeout(() => {fn.apply(context, args);}, delay);};
}

如果没有显式保存上下文:

  1. 如果返回函数​​作为对象方法调用​​,箭头函数会继承正确的 this
  2. 但如果返回函数​​被直接调用​​,箭头函数会继承全局上下文
let box = document.querySelector('.box')
let x = 1
const func = () => {box.textContent = x;console.log(x);x++;
}
const debounced = debounce(func, 1000)
box.addEventListener('mousemove', debounced)

三、节流

节流:在事件被频繁触发时,固定时间间隔内只执行一次操作,忽略中间的触发

// 立即执行--时间戳
function throttle(fn, delay) {let lastTime = 0;return function (...args) {const context = this;const now = Date.now();if (now - lastTime >= delay) {fn.apply(context, args);lastTime = now;}};
}
// 延迟执行--定时器
function throttle(func, delay) {let timeout = null;return function (...args) {const context = this;if (!timeout) {timeout = setTimeout(() => {timeout = null;func.apply(context, args);}, delay);}};
}
let box = document.querySelector('.box')
let x = 1
const func = () => {box.textContent = x;console.log(x);x++;
}
const throttled = throttle(func, 1000);
box.addEventListener('mousemove', throttled);

 总结:

模式特性描述应用场景
​立即执行防抖​首次立即执行,之后间隔期内不执行,直到停止触发超过wait时间后,才能再次立即执行。登录按钮防止重复提交
​延迟执行防抖​只有最后一次触发后等待wait时间才会执行搜索框联想建议
​立即执行节流​首次立即执行,之后间隔执行页面滚动加载
​延迟执行节流​每次触发后都在延迟结束时执行每次操作都需要响应的场景
​首尾执行节流​首次触发立即执行,后续触发保证延迟结束再执行鼠标移动跟随效果

防抖函数扩展方向:

  1. ​添加立即执行选项​

    • 思路:增加 immediate 参数控制是否立即执行
    • 实现:当 immediate=true 时,首次触发立即执行并设置冷却期,冷却期内新触发重置计时器
  2. ​支持取消执行​

    • 思路:添加 cancel() 方法清除定时器
    • 应用:组件卸载时取消待执行操作
  3. ​最大等待时间​

    • 思路:添加 maxWait 参数确保不会无限延迟
    • 实现:无论触发频率多高,强制每隔 maxWait 执行一次

节流函数扩展方向:

  1. ​添加延迟执行模式​

    • 思路:使用额外定时器确保在时间窗口结束时执行
    • 工作流程:首触发立即执行 → 后续触发缓存参数 → 窗口结束执行最后一次
  2. ​时间戳+定时器结合​

    • 思路:首触发用时间戳,尾触发用定时器
    • 实现:同时支持首尾执行(leading + trailing)
  3. ​节流状态查询​

    • 思路:添加 isPending() 方法查询是否处于冷却期
    • 应用:UI 状态反馈(如显示“操作过快”提示)

四、函数柯里化

柯里化函数:分步传递参数,每次接收一个参数并返回新函数。

function curry(fn) {return function curried(...args) {// 参数数量足够时直接执行if (args.length >= fn.length) {return fn.apply(this, args);} else {// 参数不足时返回新函数return function(...nextArgs) {return curried.apply(this, [...args, ...nextArgs]);}}};
}
  • 动态绑定 this,确保被包装函数 fn 执行的 this 指向与原始调用一致
  • 确保参数完整传递,apply的第二个参数能正确展开​数组形式的参数​
const add = (a, b, c) => a + b + c;
const curriedAdd = curry(add);
console.log(curriedAdd(1)(2)(3));  // 6
console.log(curriedAdd(1, 2)(3));  // 6

 五、instanceof

instanceof:用于检查一个对象是否是某个构造函数的实例。

实现步骤:

  • 检查 right 是否为构造函数(函数类型)
  • 过滤 left 为原始值(null/非对象)直接返回 false
  • 获取 left 的当前原型 proto
  • 获取构造函数的 prototype 属性
  • 沿原型链向上查找
  • 找到与构造函数原型匹配时返回 true
  • 原型链顶端(proto === null)返回 false
function myInstanceof(obj, fn) {// 校验右侧为构造函数if (typeof fn !== 'function') {throw new Error();}// 过滤原始值if (obj === null || typeof obj !== 'object') {return false;}let proto = Object.getPrototypeOf(obj);const prototype = fn.prototype;while (proto !== null) {if (proto === prototype) return true;proto = Object.getPrototypeOf(proto);}return false;
}
class Parent {}
class Child extends Parent {}
const obj = new Child();console.log('\ninstanceof 测试:');
console.log('myInstanceof(obj, Child):', myInstanceof(obj, Child)); // true
console.log('myInstanceof(obj, Parent):', myInstanceof(obj, Parent)); // true
console.log('myInstanceof(obj, Object):', myInstanceof(obj, Object)); // true
console.log('myInstanceof([], Array):', myInstanceof([], Array)); // true
console.log('myInstanceof(123, Number):', myInstanceof(123, Number)); // false

六、typeof

typeof:用于返回一个值的数据类型字符串。

  • 优先处理 null 返回 'null'
  • 非对象类型直接返回 typeof 结果
  • 调用 Object.prototype.toString.call(value)
  • 截取 [object Type] 中的 Type 部分
  • 统一转为小写(如 'Array' → 'array'
function myTypeof(value) {// 处理 null 的特殊情况if (value === null) return 'null';// 处理引用类型if (typeof value === 'object') {// 使用 Object.prototype.toString 精确判断类型const typeString = Object.prototype.toString.call(value);// 提取类型字符串中的实际类型return typeString.slice(8, -1).toLowerCase();}// 处理基本类型return typeof value;
}
// 测试用例
console.log(myTypeof(42));               // 'number'
console.log(myTypeof('hello'));          // 'string'
console.log(myTypeof(true));             // 'boolean'
console.log(myTypeof(undefined));        // 'undefined'
console.log(myTypeof(null));             // 'null'
console.log(myTypeof({}));               // 'object'
console.log(myTypeof([]));               // 'array'
console.log(myTypeof(/regex/));          // 'regexp'
console.log(myTypeof(new Date()));       // 'date'
console.log(myTypeof(() => {}));         // 'function'
console.log(myTypeof(Symbol()));         // 'symbol'
console.log(myTypeof(new Map()));        // 'map'
console.log(myTypeof(new Set()));        // 'set'

http://www.xdnf.cn/news/1065727.html

相关文章:

  • leetcode51.N皇后:回溯算法与冲突检测的核心逻辑
  • Linux——6.检测磁盘空间、处理数据文件
  • 【分布式技术】Bearer Token以及MAC Token深入理解
  • Python商务数据分析——Python 入门基础知识学习笔记
  • Node.js特训专栏-实战进阶:6. MVC架构在Express中的应用
  • C++智能指针编程实例
  • 目标检测neck算法之MPCA和FSA的源码实现
  • UE5 游戏模板 —— ThirdPersonGame
  • 深度解析云计算网络架构:VLAN+OVS+Bonding构建高可靠虚拟化平台
  • 给同一个wordpress网站绑定多个域名的实现方法
  • 人工智能、机器人最容易取哪些体力劳动和脑力劳动
  • 《计算机网络:自顶向下方法(第8版)》Chapter 8 课后题
  • 从零开始手写redis(16)实现渐进式 rehash map
  • (码云gitee)IDEA新项目自动创建gitee仓库并直接提交
  • 【Datawhale组队学习202506】YOLO-Master task03 IOU总结
  • 【51单片机】串口通信
  • 在windows上使用file命令
  • 2140、解决智力问题
  • 核心概念解析:AI、数据挖掘、机器学习与深度学习的关系
  • P99延迟:系统性能优化的关键指标
  • 管理综合知识点
  • Kafka与Zookeeper在linux上的下载记录
  • 【PyTorch项目实战】CycleGAN:无需成对训练样本,支持跨领域图像风格迁移
  • git 如何忽略某个文件夹文件
  • dijkstra(迪杰斯特拉)算法详解
  • React 核心原理与Fiber架构
  • Python 的内置函数 help
  • 【力扣 中等 C】983. 最低票价
  • Linux内核中安全创建套接字:为何inet_create未导出及正确替代方案
  • rust单体web项目模板搭建