最新消息:斯于道者,安有己道?

一些不常见但需要了解的JavaScript特性

源码 大爷 20浏览 0评论

1. 数组去重与快速查找

使用 Set 对象,其值天生唯一,查找时间复杂度为 O(1)。相比 filter + indexOf 的 O(n²) 冗余循环,性能显著提升,一行代码即可完成去重并转回数组。

const uid = [...new Set([101, 102, 102, 103])]; // [101, 102, 103]

2. 使用负索引便捷获取末尾元素

Array.at() 方法支持负数倒序定位,无需再写繁琐的 arr[arr.length-1],在 DOM 操作中取最后一个元素尤其方便。

const last = ['a', 'b', 'c'].at(-1); // 'c'

3. 对象与数组互转并过滤空值

结合 Object.entries()Object.fromEntries(),先将对象拆为键值对数组,过滤后再拼回对象。比使用 reduce 拼接更直观,常用于 URL 参数清洗等场景。

const clean = Object.fromEntries(
  Object.entries({ a: 1, b: '', c: 3 }).filter(([, v]) => v)
); // { a: 1, c: 3 }

4. 精准的空值合并与赋值

空值合并运算符 (??) 和空值赋值运算符 (??=) 仅对 nullundefined 生效。表单中的数字 0、空字符串 '' 等“假值”会被保留,设置默认配置时更安全。

const count = 0 ?? 10; // 0
const cfg = { timeout: 5000 };
cfg.retries ??= 3; // { timeout: 5000, retries: 3 }
const oldCfg = { timeout: 5000, retries: 2 };
oldCfg.retries ??= 3; // {timeout:5000, retries:2}

5. 强大的原生深拷贝

structuredClone() 可以处理 JSON.stringify 无法搞定的 MapSet、循环引用等,无需引入 lodash.cloneDeep 等第三方库。

const copy = structuredClone({ a: 1, b: { c: [2] } }); // { a: 1, b: { c: [2] } }

6. 原生货币与千分位格式化

Intl.NumberFormat 提供内置本地化规则,可自动添加千分位、货币符号,压缩后零体积,是报表、购物车金额展示的理想选择。

new Intl.NumberFormat('zh-CN', { style: 'currency', currency: 'CNY' }).format(1234); // ¥1,234.00

7. 本地化日期时间格式化

无需引入 moment.js 等库,浏览器可按区域自动输出格式化的年月日,SEO 友好且支持多语言切换。

new Intl.DateTimeFormat('zh-CN', { dateStyle: 'long' }).format(new Date('2025-12-22')); // 2025年12月22日

8. 向上查找最近的祖先元素

element.closest() 方法可根据 CSS 选择器向上查找最近的匹配祖先元素。在事件委托时,即使 DOM 层级调整也无需修改 JS 逻辑,比循环 parentNode 更健壮。

const list = e.target.closest('.list'); // <div class="list">...</div>

9. 异步监听元素进入视口

IntersectionObserver 提供异步回调,不阻塞主线程。适用于图片懒加载、无限滚动、广告曝光统计等场景,省去手动实现节流防抖的逻辑。

new IntersectionObserver(es =>
  es.forEach(e => e.isIntersecting && loadImg(e.target))
).observe(img); // 图片进入视口时触发 loadImg

10. 可取消的异步请求

结合 fetchAbortController,可以通过一个信号控制器 (abort) 取消所有监听该信号的请求,有效防止页面切换后旧数据覆盖新状态。

const ac = new AbortController();
fetch(url, { signal: ac.signal });
ac.abort(); // 请求被取消

11. 便捷的 URL 查询参数解析与操作

URLURLSearchParams 对象能自动编码/解码中文等特殊字符,提供链式增删改查 API,拼接跳转地址或反向解析都能一行完成。

const u = new URL(location.href);
u.searchParams.get('name');
u.searchParams.set('page', 2);
history.replaceState({}, '', u); // 地址栏变为 ?page=2

12. 无侵入的性能指标采集

PerformanceObserver 可监听浏览器原生暴露的性能指标(如 LCP、FID),脚本零成本注入,便于直接上报至监控平台。

new PerformanceObserver(list =>
  list.getEntries().forEach(sendMetric)
).observe({ type: 'LCP', buffered: true }); // 监听并上报 LCP 数值

13. 利用浏览器空闲时间执行任务

requestIdleCallback 会在浏览器空闲时才执行回调函数,适合处理埋点、日志上报等低优先级任务,不抢占渲染资源,提升首帧体验。

requestIdleCallback(() => sendBeacon('/log', data)); // 浏览器空闲时发送日志

14. 同源标签页间实时通信

BroadcastChannel 允许同源下的不同标签页、iframe 或 worker 之间进行实时广播通信,无需依赖 localStorage 事件轮询,登录态、主题切换可秒级同步。

const bc = new BroadcastChannel('auth');
bc.postMessage({ login: true }); // 其他标签页会收到消息

15. 根据页面可见性自动暂停任务

监听 visibilitychange 事件,可在页面切至后台时自动暂停视频、动画或轮询检测,节省电量与流量,用户切回前台时再自动恢复。

document.addEventListener('visibilitychange', () =>
  document.hidden ? video.pause() : video.play()
); // 后台暂停,前台恢复播放

16. 唤起系统原生分享面板

在 HTTPS 环境下,navigator.share() 可直接唤起设备(或浏览器)的原生分享面板,支持分享标题、链接、文件等,无需集成第三方 SDK。

navigator.share?.({ title: '好文', url: location.href }); // 弹出系统分享面板

17. 保持屏幕常亮

navigator.wakeLock API 允许在视频会议、PPT 演示等场景下请求保持屏幕常亮,任务结束后自动释放,用户无需手动修改系统设置。

await navigator.wakeLock.request('screen'); // 屏幕保持常亮

18. 浏览器内置取色器

EyeDropper API 提供浏览器级的吸管工具,可一键拾取屏幕上任意像素的颜色值,返回标准十六进制字符串,适合主题配色、在线设计等场景。

const { sRGBHex } = await new EyeDropper().open(); // 例如 '#ff5722'

19. 访问本地文件系统

File System Access API 在用户授权后,允许 Web 应用读写用户设备上的真实文件,可用于实现 Web IDE、断点续写、本地 Git 管理等功能,体验媲美桌面应用。

const [fh] = await showOpenFilePicker();
const text = await (await fh.getFile()).text(); // 读取文件内容为字符串

20. 跨环境的全局对象统一访问

globalThis 提供了标准化的方式访问全局对象,无论代码运行在浏览器 (window)、Web Worker (self) 还是 Node.js (global) 环境,一套代码即可搞定。

const root = globalThis; // 在浏览器中为 window

21. 快速生成指定范围的数组

Array.from() 可接受一个具有 length 属性的对象和一个映射函数,无需编写 for 循环,即可快速生成游戏排行榜、分页序号等序列数组。

const range = Array.from({ length: 5 }, (_, i) => i); // [0, 1, 2, 3, 4]

22. 安全遍历对象的自身属性

Object.keys()Object.values()Object.entries() 只遍历对象自身的可枚举属性,跳过原型链,比 for...in 更纯粹,配合数组方法使用更顺手。

Object.keys({ a: 1, b: 2 }); // ['a', 'b']

23. 灵活的对象浅拷贝与合并

Object.assign() 用于将一个或多个源对象的可枚举属性复制到目标对象,实现浅拷贝或合并。在展开运算符 (...) 出现之前广泛使用,兼容性更好。

Object.assign({}, { a: 1 }, { b: 2 }); // { a: 1, b: 2 }

24. 批量设置对象属性的默认值

空值赋值运算符 (??=) 仅在属性值为 nullundefined 时进行赋值,对已有值(包括 0false'')零侵入,非常适合初始化配置对象。

const cfg = {};
cfg.timeout ??= 5000; // 因为 timeout 是 undefined,所以被赋值为 5000
cfg.timeout ??= 3000; // 因为 timeout 已有值 5000,所以保持不变

25. 本地化的相对时间格式化

Intl.RelativeTimeFormat 根据语言规则,自动将时间差格式化为“几分钟前”、“几小时后”等易懂字符串,是社交 Feed 时间戳的利器。

new Intl.RelativeTimeFormat('zh').format(-3, 'minute'); // "3 分钟前"

26. 自动判断单复数形式

Intl.PluralRules 根据数字和语言区域,自动返回对应的复数类别(如 'zero', 'one', 'other'),告别硬编码的 if/else,让多语言文案更地道。

const rule = new Intl.PluralRules('en').select(1); // 'one'
const suffix = { one: 'item', other: 'items' }[rule]; // 'item'

27. 原生的文本分词

Intl.Segmenter 可按字、词、句对文本进行分割,适用于搜索关键词高亮、文本统计等场景,无需引入庞大的 NLP 库。

[...new Intl.Segmenter('zh').segment('JavaScript好玩')].map(i => i.segment); // ['JavaScript', '好玩']

28. 大整数精确计算

BigInt 类型可以表示任意精度的整数,解决了 Number 类型的安全整数范围限制,适用于金融、区块链等需要高精度计算的场景。

9007199254740993n + 1n; // 9007199254740994n

29. 常用的数学工具函数

Math 对象提供了一系列实用方法,如 sign (取符号)、clamp (限制范围,需自行实现或使用新提案)、hypot (计算斜边),减少 UI 动画、游戏开发中的工具函数编写。

Math.sign(-5); // -1
// 自定义 clamp 函数示例:const clamp = (num, min, max) => Math.min(Math.max(num, min), max);

30. 插入微任务

queueMicrotask() 用于将函数排入微任务队列,在当前同步任务执行完后、下一个宏任务之前立即执行。比 setTimeout(fn, 0) 时机更精准,适合框架内部批量更新 DOM。

queueMicrotask(() => updateDOM()); // 在当前同步代码执行后立即更新DOM

31. 监听元素尺寸变化

ResizeObserver 可以监听特定元素的内容区域或边框尺寸变化,比监听 window.resize 事件更细粒度,适用于图表自适应、虚拟滚动等场景。

new ResizeObserver(([entry]) => chart.resize(entry.contentRect.width)).observe(chartDom);

32. 判断元素是否匹配选择器

element.matches() 用于检查元素是否匹配指定的 CSS 选择器,在事件委托中判断事件来源时,比检查 tagNameclassList 更可靠。

if (e.target.matches('.del-btn')) {
  // 执行删除操作
}

33. 切换布尔属性状态

element.toggleAttribute() 可以一键切换元素的布尔属性(如 disabled, checked, selected)状态,省去 if/else 判断和 setAttribute/removeAttribute 的冗余代码。

btn.toggleAttribute('disabled'); // 如果 disabled 存在则移除,不存在则添加

34. 平滑滚动到指定元素

element.scrollIntoView() 方法让元素滚动到视口内,通过 { behavior: 'smooth' } 选项可启用平滑滚动效果,无需额外引入滚动库。

document.querySelector('#top').scrollIntoView({ behavior: 'smooth' }); // 平滑滚动到顶部

35. 使用关键帧创建动画

Element.animate() 是 Web Animations API 的一部分,允许使用 JavaScript 直接创建和控制关键帧动画,实现简单的淡入淡出、缩放等效果,可减少对 CSS 或 GSAP 的依赖。

el.animate([{ opacity: 0 }, { opacity: 1 }], { duration: 300 }); // 淡入动画

36. 运行时检测 CSS 特性支持

CSS.supports() 方法用于在运行时检测浏览器是否支持某个 CSS 属性或属性值,实现渐进增强时无需引入 Modernizr 等库。

if (CSS.supports('aspect-ratio', '1')) {
  // 使用 aspect-ratio
} else {
  // 使用 padding hack 等兜底方案
}

37. 流式读取响应数据

ReadableStream 允许以流的方式处理数据,可以边下载边渲染,避免大文件一次性加载导致内存暴涨,适用于视频预览、日志实时输出等场景。

const reader = response.body.getReader();
while (true) {
  const { done, value } = await reader.read();
  if (done) break;
  // 处理每一块数据 value
}

38. 后台持续下载

Background Fetch API 允许 PWA 在用户切到后台甚至关闭浏览器后,仍能继续下载大文件(如课程视频),并在网络恢复后自动重连。

await registration.backgroundFetch.fetch('my-video', ['/video.mp4']);

39. 可控的请求/响应缓存

CacheStorage (caches) 提供了比 localStorage 更专业、容量更大的存储机制,专门用于缓存网络请求的响应(如脚本、图片、API 数据),是构建离线应用的核心。

const cache = await caches.open('my-cache-v1');
await cache.add('/api/data.json'); // 缓存该请求的响应

40. 查询存储空间使用情况

navigator.storage.estimate() 返回当前源站的存储空间使用量和配额,可用于在下载大型资源(如游戏、离线包)前向用户提示剩余空间。

const { usage, quota } = await navigator.storage.estimate();
console.log(`已用: ${usage}, 总量: ${quota}`);

41. 监听网络连接状态

navigator.onLine 属性及 online/offline 事件,提供了简单的网络状态检测能力,可用于实现弱网提示、离线缓存切换等。

window.addEventListener('offline', () => showToast('网络已断开,正在使用离线缓存'));

42. 捕获浏览器发出的警告

ReportingObserver 可以捕获浏览器主动发出的各种报告,如废弃 API 的使用、CSP 违规等,便于开发者提前发现潜在问题并上报监控。

new ReportingObserver((reports) => {
  reports.forEach(report => sendToMonitoringService(report));
}).observe();

43. 高性能音视频编解码

WebCodecs API 提供了对底层音视频编解码器的访问,可以实现高性能、低延迟的播放、处理与转码,适用于在线剪辑、云游戏等场景。

const decoder = new VideoDecoder({
  output: frame => { /* 渲染视频帧 */ },
  error: e => console.error(e)
});
decoder.configure({ codec: 'vp09.00.10.08' });
// ... 喂入编码数据块 (EncodedVideoChunk)

44. 异步读写剪贴板

Clipboard API 提供了基于 Promise 的异步剪贴板读写接口,比传统的 document.execCommand 更安全易用,在 HTTPS 环境下可复制文本或图片。

await navigator.clipboard.writeText('这是要复制的文本');
const text = await navigator.clipboard.readText();

45. 获取所有 Promise 的最终状态

Promise.allSettled() 等待一组 Promise 全部敲定(无论成功或失败),返回每个 Promise 的结果描述对象。相比 Promise.all() 的“一损俱损”,它更适用于需要部分成功结果的批量操作。

const results = await Promise.allSettled([fetchA(), fetchB()]);
const successfulResults = results.filter(r => r.status === 'fulfilled');

46. 支持中断的可迭代对象遍历

for...of 循环可以遍历任何实现了可迭代协议的对象(如 Array, String, Map, Set, NodeList)。它支持 breakcontinuereturn,比 forEach 更灵活。

for (const num of numbers) {
  if (num > 10) break; // 可以提前退出循环
  console.log(num);
}

47. 将 URL 查询参数快速转为对象

结合 URLSearchParamsObject.fromEntries(),可以一行代码将查询字符串(如 ?page=2&name=foo)解析为普通对象,自动处理编码。

const params = Object.fromEntries(new URLSearchParams(location.search)); // 例如 { page: '2', name: 'foo' }

48. 以表格形式输出结构化数据

console.table() 可以将数组或对象以清晰的表格形式打印到控制台,字段自动对齐,便于调试时快速查看数据结构。

const users = [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }];
console.table(users);

49. 在源码中设置动态断点

在代码中直接写入 debugger; 语句,当浏览器开发者工具打开时,代码执行到此处会自动暂停(断点),方便逐行调试、查看调用栈和变量。

function processData(data) {
  // ... 一些逻辑
  debugger; // 执行到这里会暂停
  // ... 后续逻辑
}

50. 安全地为对象批量设置默认值

空值赋值运算符 (??=) 的批量使用,可以简洁安全地初始化配置对象,确保只对未定义(null/undefined)的属性赋默认值,避免覆盖用户已有的有效配置。

const userConfig = { theme: 'dark' };
const defaultConfig = {
  theme: 'light',
  fontSize: 14,
  saveInterval: 30000
};

// 安全地合并默认值
userConfig.theme ??= defaultConfig.theme; // 不会覆盖,因为 theme 已有值 ‘dark’
userConfig.fontSize ??= defaultConfig.fontSize; // 被赋值为 14
userConfig.saveInterval ??= defaultConfig.saveInterval; // 被赋值为 30000

收藏即生产力,2026 年用原生 API 让你的代码性能更优、体积更小 ⚡️!

转载请注明:追风逐雨 » 一些不常见但需要了解的JavaScript特性

您必须 登录 才能发表评论!