简洁函数库版

/**
 * js-utils.js
 * 实用原生 JS 工具函数合集(支持按需 import)
 * 现代浏览器 / Node ESM 通用
 */

/* ------------------ 数组与集合 ------------------ */

/**
 * 数组去重(基于 Set)
 * @param {Array} arr
 * @returns {Array}
 */
export const uniqArray = (arr) => [...new Set(arr)];

/**
 * 判断元素是否已存在(Set 快速查找)
 * @param {Set} set
 * @param {*} value
 * @returns {boolean}
 */
export const hasInSet = (set, value) => set.has(value);

/* ------------------ 对象操作 ------------------ */

/**
 * 过滤对象中的空值字段(空字符串、null、undefined)
 * @param {Object} obj
 * @returns {Object}
 */
export const filterEmptyFields = (obj) =>
  Object.fromEntries(Object.entries(obj).filter(([_, v]) => v != null && v !== ""));

/**
 * 对象数组互转
 * @param {Object} obj
 * @returns {Array<[string, any]>}
 */
export const toEntries = (obj) => Object.entries(obj);

/**
 * 将 entries 数组转为对象
 * @param {Array<[string, any]>} entries
 * @returns {Object}
 */
export const fromEntries = (entries) => Object.fromEntries(entries);

/* ------------------ 默认值处理 ------------------ */

/**
 * 安全获取默认值(只判断 null/undefined)
 * @param {*} value
 * @param {*} defaultValue
 * @returns {*}
 */
export const safeDefault = (value, defaultValue) => value ?? defaultValue;

/**
 * 对象属性安全赋默认值(仅在属性为 null/undefined 时生效)
 * @param {Object} obj
 * @param {string} key
 * @param {*} defaultValue
 */
export const ensureDefault = (obj, key, defaultValue) => {
  obj[key] ??= defaultValue;
};

/* ------------------ 国际化 ------------------ */

/**
 * 本地化货币格式化
 * @param {number} value
 * @param {string} locale 例如 "zh-CN"、"en-US"
 * @param {string} currency 例如 "CNY"、"USD"
 * @returns {string}
 */
export const formatCurrency = (value, locale = "zh-CN", currency = "CNY") =>
  new Intl.NumberFormat(locale, { style: "currency", currency }).format(value);

/**
 * 本地化日期格式化
 * @param {Date} date
 * @param {string} locale
 * @returns {string}
 */
export const formatDateTime = (date = new Date(), locale = "zh-CN") =>
  new Intl.DateTimeFormat(locale, {
    year: "numeric",
    month: "long",
    day: "numeric",
    hour: "2-digit",
    minute: "2-digit",
    second: "2-digit",
  }).format(date);

/* ------------------ DOM 工具 ------------------ */

/**
 * 懒加载图片(IntersectionObserver)
 * @param {string} selector 图片选择器
 */
export const lazyLoadImages = (selector = ".lazy-img") => {
  const observer = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        const img = entry.target;
        img.src = img.dataset.src;
        observer.unobserve(img);
      }
    });
  });
  document.querySelectorAll(selector).forEach((img) => observer.observe(img));
};

/**
 * 向上查找最近的匹配父元素
 * @param {Element} element
 * @param {string} selector
 * @returns {Element|null}
 */
export const findClosest = (element, selector) => element.closest(selector);

/* ------------------ Promise 工具 ------------------ */

/**
 * 批量请求(不因单个失败中断)
 * @param {Array<Promise>} promises
 * @returns {Promise<{fulfilled: any[], rejected: any[]}>}
 */
export const allSettledSafe = async (promises) => {
  const results = await Promise.allSettled(promises);
  return {
    fulfilled: results
      .filter((r) => r.status === "fulfilled")
      .map((r) => r.value),
    rejected: results
      .filter((r) => r.status === "rejected")
      .map((r) => r.reason),
  };
};

/* ------------------ URL 工具 ------------------ */

/**
 * 解析 URL 参数为对象
 * @param {string} url
 * @returns {Object}
 */
export const parseUrlParams = (url) =>
  Object.fromEntries(new URL(url).searchParams.entries());

/**
 * 设置 URL 参数(返回新 URL)
 * @param {string} baseUrl
 * @param {Object} params
 * @returns {string}
 */
export const buildUrl = (baseUrl, params = {}) => {
  const url = new URL(baseUrl);
  Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
  return url.href;
};

/* ------------------ 迭代工具 ------------------ */

/**
 * 安全遍历(支持 break / continue)
 * @param {Iterable} iterable
 * @param {Function} callback
 */
export const forOf = (iterable, callback) => {
  for (const item of iterable) {
    const result = callback(item);
    if (result === false) break; // 手动中断
  }
};

/* ------------------ 模块异步加载 ------------------ */

/**
 * 动态导入模块(Top-level await 替代)
 * @param {string} path
 * @returns {Promise<*>}
 */
export const importAsync = async (path) => await import(path);

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值