常用准标准库
什么是准标准库?
准标准库是指虽然不是 JavaScript 官方标准,但在社区中被广泛使用、几乎成为事实标准的工具库和实用函数。这些库已经成为现代 JavaScript 开发不可或缺的一部分。
Fetch API - 现代网络请求
Fetch API 是现代浏览器提供的原生网络请求接口,Promise-based,简洁强大。
// 基本 GET 请求
async function getData() {
try {
const response = await fetch('/api/users');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error('Fetch error:', error);
throw error;
}
}
// POST 请求
async function postData(url, data) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
return response.json();
}
// PUT 请求
async function updateData(url, data) {
const response = await fetch(url, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
return response.json();
}
// DELETE 请求
async function deleteData(url) {
const response = await fetch(url, {
method: 'DELETE',
});
return response.status === 204;
}
Fetch 高级用法
// 添加查询参数
function fetchWithParams(url, params) {
const queryString = new URLSearchParams(params).toString();
const fullUrl = queryString ? `${url}?${queryString}` : url;
return fetch(fullUrl);
}
// 使用示例
fetchWithParams('/api/users', { page: 1, limit: 10 });
// 设置超时
function fetchWithTimeout(url, options = {}, timeout = 5000) {
return Promise.race([
fetch(url, options),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Request timeout')), timeout)
)
]);
}
// 使用示例
try {
const data = await fetchWithTimeout('/api/data', {}, 3000);
} catch (error) {
console.error('请求超时:', error);
}
// 请求取消 (AbortController)
function fetchWithCancel(url) {
const controller = new AbortController();
const signal = controller.signal;
const promise = fetch(url, { signal });
return {
promise,
cancel: () => controller.abort()
};
}
// 使用示例
const { promise, cancel } = fetchWithCancel('/api/data');
setTimeout(() => cancel(), 1000); // 1秒后取消
Fetch 最佳实践
// 封装 Fetch API
class ApiClient {
constructor(baseURL, options = {}) {
this.baseURL = baseURL;
this.defaultOptions = {
headers: {
'Content-Type': 'application/json',
},
...options
};
}
async request(endpoint, options = {}) {
const url = `${this.baseURL}${endpoint}`;
const config = { ...this.defaultOptions, ...options };
try {
const response = await fetch(url, config);
if (!response.ok) {
const error = new Error(`HTTP ${response.status}: ${response.statusText}`);
error.status = response.status;
throw error;
}
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
return response.json();
}
return response.text();
} catch (error) {
console.error('API request failed:', error);
throw error;
}
}
get(endpoint, params = {}) {
const queryString = new URLSearchParams(params).toString();
const url = queryString ? `${endpoint}?${queryString}` : endpoint;
return this.request(url, { method: 'GET' });
}
post(endpoint, data) {
return this.request(endpoint, {
method: 'POST',
body: JSON.stringify(data)
});
}
put(endpoint, data) {
return this.request(endpoint, {
method: 'PUT',
body: JSON.stringify(data)
});
}
delete(endpoint) {
return this.request(endpoint, { method: 'DELETE' });
}
}
// 使用示例
const api = new ApiClient('https://api.example.com');
const users = await api.get('/users');
const user = await api.get('/users/1');
const newUser = await api.post('/users', { name: '张三' });
const updatedUser = await api.put('/users/1', { name: '李四' });
await api.delete('/users/1');
Axios - HTTP 客户端
Axios 是基于 Promise 的 HTTP 客户端,支持浏览器和 Node.js,功能比 Fetch 更丰富。
// 安装
npm install axios
// 基本使用
import axios from 'axios';
// GET 请求
axios.get('/api/users')
.then(response => console.log(response.data))
.catch(error => console.error(error));
// POST 请求
axios.post('/api/users', {
name: '张三',
email: 'zhangsan@example.com'
})
.then(response => console.log(response.data));
// PUT 请求
axios.put('/api/users/1', { name: '李四' });
// DELETE 请求
axios.delete('/api/users/1');
Axios 高级功能
// 并发请求
function getMultipleData() {
return axios.all([
axios.get('/api/users'),
axios.get('/api/posts'),
axios.get('/api/comments')
]).then(axios.spread((users, posts, comments) => {
return { users: users.data, posts: posts.data, comments: comments.data };
}));
}
// 请求拦截器
axios.interceptors.request.use(
config => {
// 在发送请求之前做些什么
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
},
error => {
// 对请求错误做些什么
return Promise.reject(error);
}
);
// 响应拦截器
axios.interceptors.response.use(
response => {
// 对响应数据做点什么
return response;
},
error => {
// 对响应错误做点什么
if (error.response?.status === 401) {
// 处理未授权
window.location.href = '/login';
}
return Promise.reject(error);
}
);
// 超时设置
axios.get('/api/data', { timeout: 5000 });
// 取消请求
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get('/api/data', {
cancelToken: source.token
});
source.cancel('Operation canceled by the user.');
Axios 实例封装
// 创建 Axios 实例
const api = axios.create({
baseURL: 'https://api.example.com',
timeout: 10000,
headers: {
'Content-Type': 'application/json',
'X-Custom-Header': 'value'
}
});
// 请求拦截器
api.interceptors.request.use(
config => {
const token = localStorage.getItem('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
}
);
// 响应拦截器
api.interceptors.response.use(
response => response,
error => {
if (error.response?.status === 401) {
window.location.href = '/login';
}
return Promise.reject(error);
}
);
// 封装 API 方法
export const userApi = {
getUsers: (params) => api.get('/users', { params }),
getUser: (id) => api.get(`/users/${id}`),
createUser: (data) => api.post('/users', data),
updateUser: (id, data) => api.put(`/users/${id}`, data),
deleteUser: (id) => api.delete(`/users/${id}`)
};
// 使用
import { userApi } from './api';
const users = await userApi.getUsers({ page: 1, limit: 10 });
const user = await userApi.getUser(1);
await userApi.deleteUser(1);
Fetch vs Axios
// Fetch - 原生,轻量
// ✅ 浏览器原生支持
// ✅ 无需额外依赖
// ❌ 需要手动处理很多细节
// ❌ 不支持请求取消 (需要 AbortController)
// ❌ 不支持请求/响应拦截器
fetch('/api/users')
.then(response => {
if (!response.ok) throw new Error('Error');
return response.json();
})
.then(data => console.log(data));
// Axios - 功能丰富
// ✅ 自动 JSON 转换
// ✅ 请求/响应拦截器
// ✅ 请求取消
// ✅ 自动超时
// ✅ 更好的错误处理
// ✅ 并发请求支持
// ❌ 需要额外依赖 (~13KB)
axios.get('/api/users')
.then(response => console.log(response.data))
.catch(error => console.error(error));
Lodash - JavaScript 实用工具库
Lodash 是最受欢迎的 JavaScript 实用工具库,提供了模块化、高性能的工具函数。
// 数组操作
import { chunk, uniq, sortBy } from 'lodash';
const numbers = [1, 2, 3, 4, 5];
console.log(chunk(numbers, 2)); // [[1,2], [3,4], [5]]
console.log(uniq([1, 2, 2, 3])); // [1, 2, 3]
console.log(sortBy(users, 'age')); // 按年龄排序
// 对象操作
import { get, set, merge, omit } from 'lodash';
const user = { profile: { name: '张三' } };
console.log(get(user, 'profile.name')); // '张三'
console.log(get(user, 'profile.email', 'default@email.com')); // 默认值
const newUser = set({}, 'profile.age', 25);
const merged = merge({}, defaults, options);
const cleaned = omit(user, ['password', 'token']);
// 函数式编程
import { debounce, throttle, memoize } from 'lodash';
const debouncedSearch = debounce((query) => {
fetchSearchResults(query);
}, 300);
const throttledScroll = throttle(() => {
handleScroll();
}, 100);
const expensive = memoize((n) => {
return complexCalculation(n);
});
Lodash 深入使用
// 深度克隆
import { cloneDeep, merge } from 'lodash';
const original = {
name: '张三',
profile: {
age: 25,
address: { city: '北京' }
}
};
const cloned = cloneDeep(original);
cloned.profile.address.city = '上海';
console.log(original.profile.address.city); // '北京' (原对象不变)
// 深度合并
const defaults = {
theme: 'light',
language: 'en',
features: {
notifications: true
}
};
const options = {
language: 'zh',
features: {
darkMode: true
}
};
const merged = merge({}, defaults, options);
// { theme: 'light', language: 'zh', features: { notifications: true, darkMode: true } }
Day.js - 轻量级日期库
Day.js 是 Moment.js 的轻量级替代品,API 相似但体积只有 2KB。
import dayjs from 'dayjs';
import relativeTime from 'dayjs/plugin/relativeTime';
import utc from 'dayjs/plugin/utc';
dayjs.extend(relativeTime);
dayjs.extend(utc);
// 基本使用
const now = dayjs();
console.log(now.format('YYYY-MM-DD HH:mm:ss')); // '2024-01-26 15:30:00'
// 操作日期
const tomorrow = dayjs().add(1, 'day');
const lastMonth = dayjs().subtract(1, 'month');
// 相对时间
console.log(dayjs('2024-01-01').fromNow()); // '25 days ago'
// 时区处理
const utcTime = dayjs.utc();
const localTime = dayjs.utc().local();
// 解析和格式化
const date = dayjs('2024-01-26', 'YYYY-MM-DD');
console.log(date.format('MMMM D, YYYY')); // 'January 26, 2026' (英文)
console.log(date.locale('zh-cn').format('YYYY年MM月DD日')); // 中文
date-fns - 现代日期库
date-fns 是现代 JavaScript 日期处理库,模块化、不可变、Tree-shakable。
// 安装
npm install date-fns
// 基本使用
import {
format,
addDays,
subDays,
differenceInDays,
isAfter,
isBefore,
startOfDay,
endOfDay,
eachDayOfInterval,
parseISO
} from 'date-fns';
const now = new Date();
// 格式化日期
console.log(format(now, 'yyyy-MM-dd')); // '2024-01-26'
console.log(format(now, 'yyyy年MM月dd日')); // '2024年01月26日'
console.log(format(now, 'yyyy-MM-dd HH:mm:ss')); // '2024-01-26 15:30:00'
// 日期操作
const tomorrow = addDays(now, 1);
const yesterday = subDays(now, 1);
const nextWeek = addDays(now, 7);
// 日期比较
const date1 = new Date('2024-01-01');
const date2 = new Date('2024-01-26');
console.log(isAfter(date2, date1)); // true
console.log(isBefore(date1, date2)); // true
// 日期差
const daysDiff = differenceInDays(date2, date1); // 25
date-fns 高级用法
// 时区处理 (需要额外安装)
import { zonedTimeToUtc, utcToZonedTime, format } from 'date-fns-tz';
import 'date-fns-tz/locale/zh-CN';
const timeZone = 'Asia/Shanghai';
const now = new Date();
// UTC 转换为时区
const zonedDate = utcToZonedTime(now, timeZone);
// 格式化时区日期
console.log(format(zonedDate, 'yyyy-MM-dd HH:mm:ss', { timeZone }));
// 国际化 (i18n)
import { format, zhCN } from 'date-fns/locale';
import { differenceInDays } from 'date-fns';
console.log(format(now, 'PPP', { locale: zhCN })); // '2024年1月26日'
// 相对时间
import { formatDistanceToNow, formatDistance } from 'date-fns';
const pastDate = new Date('2024-01-20');
console.log(formatDistanceToNow(pastDate, { locale: zhCN })); // '大约6天前'
// 日期解析
import { parse, parseISO, isValid } from 'date-fns';
const parsedDate = parse('2024-01-26', 'yyyy-MM-dd', new Date());
const isoDate = parseISO('2024-01-26T15:30:00');
if (isValid(parsedDate)) {
console.log('日期有效');
}
// 业务日历
import {
isWeekend,
isMonday,
isFriday,
getWeek,
getMonth,
getYear,
startOfMonth,
endOfMonth
} from 'date-fns';
console.log(isWeekend(now)); // 是否周末
console.log(isMonday(now)); // 是否周一
console.log(getWeek(now)); // 周数
console.log(startOfMonth(now)); // 月初
console.log(endOfMonth(now)); // 月末
date-fns vs Day.js
// Day.js - 简单易用,类似 Moment.js
import dayjs from 'dayjs';
// 链式调用
const result = dayjs()
.add(1, 'day')
.subtract(1, 'month')
.format('YYYY-MM-DD');
// ✅ API 简洁,易于理解
// ✅ 体积小 (~2KB)
// ✅ 链式调用
// ❌ 不是模块化的
// date-fns - 模块化,函数式
import { format, addDays, subMonths } from 'date-fns';
// 函数式调用
const result2 = format(
subMonths(addDays(new Date(), 1), 1),
'yyyy-MM-dd'
);
// ✅ 完全模块化
// ✅ 函数式,可组合
// ✅ 不可变
// ✅ Tree-shakable
// ❌ API 相对复杂
// ❌ 需要多个 import
Zepto - 轻量级 jQuery 替代
Zepto 是轻量级的现代浏览器库,API 与 jQuery 兼容,但体积更小 (~10KB)。
// 安装
npm install zepto
// 基本 DOM 操作
import $ from 'zepto';
// 选择元素
const $header = $('header');
const $items = $('.item');
// 修改内容
$('新段落
').appendTo('#container');
$('.content').html('标题
');
$('.title').text('新标题');
// 样式操作
$('.box').css('background', 'red');
$('.box').addClass('active');
$('.box').removeClass('inactive');
$('.box').toggleClass('highlight');
// 事件处理
$('.button').on('click', function() {
console.log('按钮被点击');
});
$('.input').on('input', function(e) {
console.log(e.target.value);
});
// 动画
$('.box').animate({
left: '100px',
opacity: 0.5
}, 300);
Zepto vs jQuery
// jQuery - 功能丰富,但体积大 (~34KB)
// ✅ 功能全面
// ✅ 广泛使用
// ✅ 文档完善
// ❌ 体积大
// ❌ 性能相对较低
// Zepto - 轻量级,现代浏览器
// ✅ 体积小 (~10KB)
// ✅ 性能好
// ✅ API 与 jQuery 兼容
// ✅ 移动端友好
// ❌ 不支持 IE
// ❌ 功能相对较少
// 选择合适的库
// - 老项目、需要 IE 支持: jQuery
// - 现代浏览器、移动端: Zepto 或 原生 API
// - 新项目: 推荐使用原生 API 或框架
选择合适的库
- 网络请求 - Axios (功能丰富) 或 Fetch (原生)
- 日期处理 - Day.js (简单) 或 date-fns (模块化)
- 工具函数 - Lodash (功能丰富)
- DOM 操作 - Zepto (兼容 jQuery) 或 原生 API
- 优先使用浏览器原生 API - 如 URLSearchParams、Blob、File API
- 选择轻量级库 - 如 Day.js (2KB) 而不是 Moment.js (67KB)
- 考虑 Tree-shaking - 选择支持 ES Module 的库
- 维护活跃 - 选择持续更新的库
- 类型支持 - 优先选择有 TypeScript 定义的库
- 安全性 - 特别注意用户输入处理的库