我工作8年,总结的20个高效开发的JS工具函数

1,765 阅读6分钟

在前端领域摸爬滚打了8年,从一个写 if/else 都心惊胆战的小白,到现在能从容应对各种复杂业务的老兵,我发现,真正拉开开发者之间效率差距的,除了经验和对框架的理解外,还有一个常常被忽略的“秘密武器”——一个属于自己的、顺手的工具函数库

我们总说“Don't Repeat Yourself (DRY)”,但很多时候,我们仍在不同项目中反复编写着同样逻辑的代码,比如:深拷贝、防抖、节流、获取URL参数等等。

今天,我将这8年来沉淀、打磨、筛选出的20个最高频、最实用的JavaScript工具函数分享给你。它们全部是原生JS或ES6+实现,无任何依赖,你可以直接复制到你的项目中使用。

1. 防抖 (Debounce)

场景:防止函数在短时间内被高频触发,常用于输入框搜索、窗口大小调整等。

代码

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

// 使用示例
const debouncedSearch = debounce(() => console.log('Searching...'), 500);
window.addEventListener('input', debouncedSearch);

2. 节流 (Throttle)

场景:保证函数在一定时间间隔内只执行一次,常用于监听滚动事件、拖拽事件。

代码

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

// 使用示例
const throttledScroll = throttle(() => console.log('Scrolling...'), 1000);
window.addEventListener('scroll', throttledScroll);

3. 深拷贝 (Deep Clone)

场景:完全复制一个对象,包括其嵌套的对象和数组,断开引用关系。

注意: 这是简易版,对于更复杂的场景(如循环引用、特殊对象类型),推荐使用 structuredClone (现代浏览器原生支持) 或 lodash.cloneDeep。

代码

function deepClone(obj, hash = new WeakMap()) {
  if (obj === null || typeof obj !== 'object') return obj;
  if (hash.has(obj)) return hash.get(obj);

  const cloneObj = Array.isArray(obj) ? [] : {};
  hash.set(obj, cloneObj);

  for (let key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      cloneObj[key] = deepClone(obj[key], hash);
    }
  }
  return cloneObj;
}

// 使用示例
const obj1 = { a: 1, b: { c: 2 } };
const obj2 = deepClone(obj1);
obj2.b.c = 3;
console.log(obj1.b.c); // 输出 2

4. 数组去重 (Unique Array)

场景:移除数组中的重复元素。

代码

JavaScript

function uniqueArray(arr) {
  return [...new Set(arr)];
}

// 使用示例
console.log(uniqueArray([1, 1, 'a', 'a', 2, 2])); // 输出 [1, "a", 2]

5. 数组扁平化 (Flatten Array)

场景:将多维数组转化为一维数组。

代码

function flattenArray(arr) {
  return arr.reduce((acc, val) => 
    Array.isArray(val) ? acc.concat(flattenArray(val)) : acc.concat(val), 
  []);
}
// 或者使用原生方法 (ES2019)
// const flattened = arr.flat(Infinity);

// 使用示例
const nestedArray = [1, [2, [3, [4]], 5]];
console.log(flattenArray(nestedArray)); // 输出 [1, 2, 3, 4, 5]

6. 生成随机字符串 (Generate Random String)

场景:生成一个指定长度的随机字符串,常用作唯一ID。

代码

function randomString(length = 8) {
  return Math.random().toString(36).substring(2, 2 + length);
}

// 使用示例
console.log(randomString(10)); // 输出类似 "7j2k9n4p1q"

7. 首字母大写 (Capitalize)

场景:将字符串的第一个字母转换为大写。

代码

function capitalize([first, ...rest]) {
  return first.toUpperCase() + rest.join('');
}

// 使用示例
console.log(capitalize('helloWorld')); // 输出 "HelloWorld"

8. 检查对象是否为空 (Is Object Empty)

场景:判断一个对象是否没有任何自身属性。

代码

function isObjectEmpty(obj) {
  return obj && Object.keys(obj).length === 0 && obj.constructor === Object;
}

// 使用示例
console.log(isObjectEmpty({})); // true
console.log(isObjectEmpty({ a: 1 })); // false

9. 异步延迟/休眠 (Sleep)

场景:在 async/await 流程中暂停指定的毫秒数。

代码

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

// 使用示例
async function doSomething() {
  console.log('Start');
  await sleep(2000);
  console.log('End after 2 seconds');
}
doSomething();

10. 获取URL查询参数 (Get Query Params)

场景:将URL的查询字符串解析成一个对象。

代码

function getQueryParams(url = window.location.href) {
  const searchParams = new URL(url).searchParams;
  const params = {};
  for (const [key, value] of searchParams.entries()) {
    params[key] = value;
  }
  return params;
}

// 使用示例
// 假设 URL 是 "https://example.com?name=gemini&age=1"
// console.log(getQueryParams()); // 输出 { name: "gemini", age: "1" }

11. 格式化货币 (Format Currency)

场景:将数字格式化为货币字符串。

代码

function formatCurrency(amount, currency = 'CNY', locale = 'zh-CN') {
  return new Intl.NumberFormat(locale, {
    style: 'currency',
    currency: currency,
  }).format(amount);
}

// 使用示例
console.log(formatCurrency(12345.67)); // 输出 "¥12,345.67"
console.log(formatCurrency(12345.67, 'USD', 'en-US')); // 输出 "$12,345.67"

12. 复制到剪贴板 (Copy to Clipboard)

场景:将文本内容异步复制到用户剪贴板。

代码

async function copyToClipboard(text) {
  if (!navigator.clipboard) {
    console.error('Clipboard API not available');
    return Promise.reject('Clipboard API not available');
  }
  try {
    await navigator.clipboard.writeText(text);
    console.log('Copied to clipboard');
    return Promise.resolve();
  } catch (err) {
    console.error('Failed to copy: ', err);
    return Promise.reject(err);
  }
}

// 使用示例
// copyToClipboard('Hello, Gemini!');

13. 数组分块 (Chunk Array)

场景:将一个大数组按指定大小分割成多个小数组。

代码

function chunkArray(arr, size) {
  const result = [];
  for (let i = 0; i < arr.length; i += size) {
    result.push(arr.slice(i, i + size));
  }
  return result;
}

// 使用示例
const numbers = [1, 2, 3, 4, 5, 6, 7, 8];
console.log(chunkArray(numbers, 3)); // 输出 [[1, 2, 3], [4, 5, 6], [7, 8]]

14. 从对象中拾取属性 (Pick)

场景:从一个对象中选择指定的若干个属性,返回一个新对象。

代码

function pick(obj, ...keys) {
  return keys.reduce((acc, key) => {
    if (obj && Object.prototype.hasOwnProperty.call(obj, key)) {
      acc[key] = obj[key];
    }
    return acc;
  }, {});
}

// 使用示例
const user = { id: 1, name: 'Gemini', age: 1, email: 'gemini@google.com' };
console.log(pick(user, 'id', 'name')); // 输出 { id: 1, name: 'Gemini' }

15. 生成范围内的随机数 (Random in Range)

场景:获取一个介于 minmax 之间的随机整数。

代码

function randomInRange(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

// 使用示例
console.log(randomInRange(10, 20)); // 输出 10 到 20 之间的一个整数

16. 判断是否在浏览器环境 (Is Browser)

场景:在编写同构(Isomorphic)代码时,判断当前环境是否为浏览器。

代码

const isBrowser = () => typeof window !== 'undefined' && typeof window.document !== 'undefined';

// 使用示例
console.log(isBrowser()); // 在浏览器中为 true,在 Node.js 中为 false

17. 平滑滚动到顶部 (Smooth Scroll to Top)

场景:点击按钮后,页面平滑地滚动回页面顶部。

代码

function smoothScrollToTop() {
  window.scrollTo({
    top: 0,
    behavior: 'smooth',
  });
}

// 使用示例
// 在按钮的点击事件中调用 smoothScrollToTop()

18. 获取数据类型 (Get Type)

场景:比 typeof 更精确地获取一个变量的数据类型。

代码

function getType(value) {
  return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
}

// 使用示例
console.log(getType([])); // "array"
console.log(getType({})); // "object"
console.log(getType(new Date())); // "date"

19. 函数只执行一次 (Once)

场景:创建一个只能被调用一次的函数。

代码

function once(fn) {
  let hasBeenCalled = false;
  let result;
  return function(...args) {
    if (!hasBeenCalled) {
      hasBeenCalled = true;
      result = fn.apply(this, args);
    }
    return result;
  };
}

// 使用示例
const initApp = once(() => console.log('App Initialized!'));
initApp(); // 输出 "App Initialized!"
initApp(); // 不会再输出

20. 截断字符串 (Truncate String)

场景:如果字符串超过指定长度,则截断并添加省略号。

代码

function truncateString(str, maxLength) {
  if (str.length <= maxLength) return str;
  return str.slice(0, maxLength) + '...';
}

// 使用示例
const longText = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.';
console.log(truncateString(longText, 20)); // 输出 "Lorem ipsum dolor si..."

以上就是我为你精选的20个工具函数。当然,这只是冰山一角,一个强大的工具库是持续迭代和丰富的过程。你可以将它们收藏起来,根据自己的项目需求进行修改和扩展,逐步打造属于你自己的“工具库" 谢谢大家🙂

📌 你可以继续看我的系列文章