JavaScript特性笔记
1. Set 数组去重
// 事件监听防重复
const listenedEvents = new Set();
function safeAddEvent(eventName, handler) {
if (!listenedEvents.has(eventName)) {
window.addEventListener(eventName, handler);
listenedEvents.add(eventName);
}
}
2. Object.entries() + Object.fromEntries()
用法:对象⇄数组双向转换,实现高级操作
// URL参数转对象
const searchStr = "name=张三&age=28";
const paramObj = Object.fromEntries(new URLSearchParams(searchStr));
console.log(paramObj); // {name: "张三", age: "28"}
3.空值合并运算符 (??) 和赋值 (??=)
用法:只对 null 和 undefined 生效,不误判有效假值
// ?? 替换 ||
const userInputCount = 0;
const wrongCount = userInputCount || 10; // 10 (错误)
const correctCount = userInputCount ?? 10; // 0 (正确)
// 对象默认值(不覆盖已有值)
const requestConfig = { timeout: 5000 };
requestConfig.retries ??= 3; // 添加默认值
console.log(requestConfig); // {timeout: 5000, retries: 3}
4.Intl 国际化 API
用法:浏览器原生国际化,替代 moment.js 等重型库
// 多语言货币格式化
const price = 1234.56;
const cnyPrice = new Intl.NumberFormat("zh-CN", {
style: "currency",
currency: "CNY"
}).format(price); // "¥1,234.56"
// 日期本地化
const now = new Date();
const cnDate = new Intl.DateTimeFormat("zh-CN", {
year: "numeric",
month: "long",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
second: "2-digit"
}).format(now); // "2024年5月30日 14:30:25"
5.Intersection Observer API
用法:异步监听元素可见性,性能远超传统方法,实现图片懒加载和图片无限滚动加载
// todo 下面的代码可以写成工具
// 图片懒加载
const lazyObserver = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
lazyObserver.unobserve(img);
}
});
});
document.querySelectorAll(".lazy-img").forEach((img) => {
lazyObserver.observe(img);
});
// 无限滚动加载
const loadObserver = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
fetchNextPageData().then((data) => {
renderNews(data);
});
}
});
loadObserver.observe(document.getElementById("load-more"));
6. Promise.allSettled()
用法:等待所有 Promise 完成,不因单个失败而中断,Promise.all单个失败则终止
7. Element.closest()
用法:基于 CSS 选择器查找最近的祖先元素
// 输入框聚焦找到表单组
document.querySelector("input").addEventListener("focus", (e) => {
const formGroup = e.target.closest(".form-group");
formGroup.classList.add("focused");
});
8. URL + URLSearchParams
用法:原生URL处理,解析url和params
// 当前页面URL:https://xxx.com/user?name=张三&age=28&gender=男
const currentUrl = new URL(window.location.href);
// 获取参数
console.log(currentUrl.searchParams.get("name")); // "张三"
console.log(currentUrl.hostname); // "xxx.com"
console.log(currentUrl.pathname); // "/user"
// 修改URL参数
const url = new URL("https://xxx.com/list");
// 增删改查参数
url.searchParams.append("page", 2); // 添加
url.searchParams.set("page", 3); // 修改
url.searchParams.delete("size"); // 删除
console.log(url.href); // "https://xxx.com/list?page=3"
window.location.href = url.href; // 跳转
9. for...of 循环
用法:支持 break/continue,可遍历map、set
10. 顶层 await
用法:允许在模块的最外层直接使用await,而不需要包裹在async函数里
需要注意:顶层 await 会阻塞模块的执行,因此要谨慎使用
- 案例1:从服务器获取配置
// config.js
const response = await fetch('/api/config');
export const config = await response.json();
// app.js
import { config } from './config.js';
console.log(config); // 这里使用的 config 已经是获取到的配置,不需要担心异步问题
- 案例2:动态按需加载
// chart-module.js 模块本身在加载时执行一些异步操作,比如加载图表库,那么我们可以这样
const ChartLibrary = await import('https://example.com/chart-library.js');// 动态导入图表库
export function renderChart(container) {
// 使用 ChartLibrary 渲染图表
}
// main.js
document.getElementById('show-chart-btn').addEventListener('click', async () => {
const { renderChart } = await import('./chart-module.js');
renderChart('#chart-container');
});

浙公网安备 33010602011771号