前端开发中最常遇到的实用算法,包括防抖节流、深拷贝、LRU缓存等。

前端常用算法

这些是前端开发中最常遇到的实用算法,掌握它们对日常开发很有帮助。

防抖 (Debounce)

在事件被触发 n 秒后再执行回调,如果在这 n 秒内又被触发,则重新计时。 常用于搜索输入、窗口 resize 等场景。

实时输入值
-
触发次数: 0
防抖后的值
-
实际执行次数: 0
function debounce(fn, delay) {
  let timer = null;

  return function (...args) {
    // 清除之前的定时器
    clearTimeout(timer);

    // 设置新的定时器
    timer = setTimeout(() => {
      fn.apply(this, args);
    }, delay);
  };
}

// 使用示例
const debouncedSearch = debounce((query) => {
  fetch(`/api/search?q=${query}`);
}, 500);

input.addEventListener('input', (e) => {
  debouncedSearch(e.target.value);
});

节流 (Throttle)

规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次,只有一次生效。 常用于滚动事件、按钮点击防重复等场景。

向下滚动查看效果(每 200ms 最多触发一次)

原始触发次数
0
节流后触发次数
0
滚动位置
0px
// 时间戳版本
function throttle(fn, limit) {
  let lastTime = 0;

  return function (...args) {
    const now = Date.now();
    if (now - lastTime >= limit) {
      fn.apply(this, args);
      lastTime = now;
    }
  };
}

// 定时器版本
function throttle(fn, limit) {
  let inThrottle = false;

  return function (...args) {
    if (!inThrottle) {
      fn.apply(this, args);
      inThrottle = true;
      setTimeout(() => (inThrottle = false), limit);
    }
  };
}

LRU 缓存(LeetCode 146)

LRU (Least Recently Used) 最近最少使用缓存。当缓存满时,删除最久未使用的数据。 使用 Map 可以保持插入顺序,实现 O(1) 的 get 和 put。

缓存状态 (容量: 3, 当前: 0)
空缓存
class LRUCache {
  constructor(capacity) {
    this.capacity = capacity;
    this.cache = new Map();
  }

  get(key) {
    if (!this.cache.has(key)) return -1;

    // 更新为最近使用
    const value = this.cache.get(key);
    this.cache.delete(key);
    this.cache.set(key, value);
    return value;
  }

  put(key, value) {
    // 如果已存在,先删除
    if (this.cache.has(key)) {
      this.cache.delete(key);
    } else if (this.cache.size >= this.capacity) {
      // 删除最久未使用的(Map 第一个)
      const firstKey = this.cache.keys().next().value;
      this.cache.delete(firstKey);
    }
    this.cache.set(key, value);
  }
}

深拷贝 (Deep Clone)

深拷贝会复制对象的所有层级,修改副本不会影响原对象。这是开发中常见的需求。

原对象
{
  "name": "张三",
  "age": 25,
  "hobbies": [
    "读书",
    "游戏"
  ],
  "address": {
    "city": "北京",
    "district": "朝阳区"
  },
  "date": "2026-03-13T07:39:10.252Z"
}
克隆对象
点击按钮执行深拷贝
JSON 方法局限
  • 无法处理 undefined、Symbol、函数
  • 无法处理循环引用
  • Date 会变成字符串
  • RegExp 会变成空对象
递归实现优点
  • 可以处理特殊类型
  • 可以处理循环引用(WeakMap)
  • 可以自定义处理逻辑
function deepClone(obj, hash = new WeakMap()) {
  // 基本类型直接返回
  if (obj === null || typeof obj !== 'object') {
    return obj;
  }

  // 处理特殊对象
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);

  // 处理循环引用
  if (hash.has(obj)) return hash.get(obj);

  // 创建新对象/数组
  const clone = Array.isArray(obj) ? [] : {};
  hash.set(obj, clone);

  // 递归复制属性
  for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
      clone[key] = deepClone(obj[key], hash);
    }
  }

  return clone;
}

数组扁平化 (Flatten)

深度:
原数组
[1,[2,[3,[4,5]]],6,[7,8]]
扁平化结果
点击按钮执行
// 递归实现
function flatten(arr, depth = Infinity) {
  if (depth === 0) return arr.slice();

  return arr.reduce((acc, val) => {
    if (Array.isArray(val)) {
      acc.push(...flatten(val, depth - 1));
    } else {
      acc.push(val);
    }
    return acc;
  }, []);
}

// ES6 原生方法
arr.flat(depth);  // depth 默认为 1
arr.flat(Infinity);  // 完全扁平化