Appearance
JavaScript 实用技巧与最佳实践
🎯 现代 JavaScript 特性
1. 解构赋值
javascript
// ✅ 对象解构
const user = { name: '阿超', age: 28, city: '北京' }
const { name, age, city = '上海' } = user
// ✅ 数组解构
const colors = ['red', 'green', 'blue']
const [primary, secondary, ...rest] = colors
// ✅ 函数参数解构
function createUser({ name, email, age = 18 }) {
return { name, email, age, id: Date.now() }
}
// ✅ 嵌套解构
const response = {
data: {
user: { name: '阿超', profile: { avatar: 'avatar.jpg' } }
}
}
const { data: { user: { name: userName, profile: { avatar } } } } = response
2. 模板字符串
javascript
// ✅ 基础用法
const name = '阿超'
const greeting = `你好,${name}!今天是 ${new Date().toLocaleDateString()}`
// ✅ 多行字符串
const html = `
<div class="card">
<h2>${title}</h2>
<p>${description}</p>
</div>
`
// ✅ 标签模板
function highlight(strings, ...values) {
return strings.reduce((result, string, i) => {
const value = values[i] ? `<mark>${values[i]}</mark>` : ''
return result + string + value
}, '')
}
const searchTerm = 'JavaScript'
const text = highlight`学习 ${searchTerm} 是很有趣的!`
3. 箭头函数与this绑定
javascript
// ✅ 箭头函数的正确使用
class Timer {
constructor() {
this.seconds = 0
}
start() {
// 箭头函数保持this绑定
setInterval(() => {
this.seconds++
console.log(`已运行 ${this.seconds} 秒`)
}, 1000)
}
// ✅ 方法简写
reset() {
this.seconds = 0
}
}
// ✅ 数组方法中的箭头函数
const numbers = [1, 2, 3, 4, 5]
const doubled = numbers.map(n => n * 2)
const evens = numbers.filter(n => n % 2 === 0)
const sum = numbers.reduce((acc, n) => acc + n, 0)
🔧 实用工具函数
1. 防抖与节流
javascript
// 防抖函数
function debounce(func, delay) {
let timeoutId
return function (...args) {
clearTimeout(timeoutId)
timeoutId = setTimeout(() => func.apply(this, args), delay)
}
}
// 节流函数
function throttle(func, delay) {
let lastCall = 0
return function (...args) {
const now = Date.now()
if (now - lastCall >= delay) {
lastCall = now
func.apply(this, args)
}
}
}
// 使用示例
const searchInput = document.getElementById('search')
const debouncedSearch = debounce((e) => {
console.log('搜索:', e.target.value)
}, 300)
searchInput.addEventListener('input', debouncedSearch)
2. 深拷贝
javascript
// 简单深拷贝(不处理函数、Date等特殊对象)
function simpleDeepClone(obj) {
return JSON.parse(JSON.stringify(obj))
}
// 完整深拷贝
function deepClone(obj, hash = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj
if (obj instanceof Date) return new Date(obj)
if (obj instanceof Array) return obj.map(item => deepClone(item, hash))
if (obj instanceof Object) {
if (hash.has(obj)) return hash.get(obj)
const cloneObj = {}
hash.set(obj, cloneObj)
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
cloneObj[key] = deepClone(obj[key], hash)
}
}
return cloneObj
}
}
3. 数组操作技巧
javascript
// ✅ 数组去重
const uniqueArray = [...new Set(array)]
// ✅ 数组扁平化
const flatArray = array.flat(Infinity)
// 或者
const flatArray2 = array.reduce((acc, val) =>
Array.isArray(val) ? acc.concat(flatArray2(val)) : acc.concat(val), [])
// ✅ 数组分组
function groupBy(array, key) {
return array.reduce((groups, item) => {
const group = item[key]
groups[group] = groups[group] || []
groups[group].push(item)
return groups
}, {})
}
const users = [
{ name: '张三', department: '技术部' },
{ name: '李四', department: '产品部' },
{ name: '王五', department: '技术部' }
]
const groupedUsers = groupBy(users, 'department')
🚀 异步编程
1. Promise 最佳实践
javascript
// ✅ Promise 链式调用
fetch('/api/user')
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
return response.json()
})
.then(user => {
console.log('用户信息:', user)
return fetch(`/api/user/${user.id}/posts`)
})
.then(response => response.json())
.then(posts => {
console.log('用户文章:', posts)
})
.catch(error => {
console.error('请求失败:', error)
})
// ✅ Promise.all 并行请求
const fetchUserData = async (userId) => {
try {
const [user, posts, comments] = await Promise.all([
fetch(`/api/user/${userId}`).then(r => r.json()),
fetch(`/api/user/${userId}/posts`).then(r => r.json()),
fetch(`/api/user/${userId}/comments`).then(r => r.json())
])
return { user, posts, comments }
} catch (error) {
console.error('获取用户数据失败:', error)
throw error
}
}
2. async/await 模式
javascript
// ✅ 错误处理
async function fetchWithRetry(url, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
const response = await fetch(url)
if (!response.ok) {
throw new Error(`HTTP ${response.status}`)
}
return await response.json()
} catch (error) {
console.log(`尝试 ${i + 1} 失败:`, error.message)
if (i === maxRetries - 1) throw error
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)))
}
}
}
// ✅ 并发控制
async function processInBatches(items, batchSize, processor) {
const results = []
for (let i = 0; i < items.length; i += batchSize) {
const batch = items.slice(i, i + batchSize)
const batchResults = await Promise.all(
batch.map(item => processor(item))
)
results.push(...batchResults)
}
return results
}
🎨 函数式编程
1. 高阶函数
javascript
// ✅ 函数组合
const compose = (...fns) => (value) => fns.reduceRight((acc, fn) => fn(acc), value)
const pipe = (...fns) => (value) => fns.reduce((acc, fn) => fn(acc), value)
// 示例
const addOne = x => x + 1
const double = x => x * 2
const square = x => x * x
const transform = pipe(addOne, double, square)
console.log(transform(3)) // ((3 + 1) * 2)² = 64
// ✅ 柯里化
const curry = (fn) => {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args)
} else {
return function (...args2) {
return curried.apply(this, args.concat(args2))
}
}
}
}
const add = curry((a, b, c) => a + b + c)
const add5 = add(5)
const add5And3 = add5(3)
console.log(add5And3(2)) // 10
2. 不可变数据操作
javascript
// ✅ 数组不可变操作
const originalArray = [1, 2, 3, 4, 5]
// 添加元素
const withNewItem = [...originalArray, 6]
const withItemAtStart = [0, ...originalArray]
// 删除元素
const withoutFirst = originalArray.slice(1)
const withoutLast = originalArray.slice(0, -1)
const withoutIndex = originalArray.filter((_, index) => index !== 2)
// 更新元素
const updated = originalArray.map((item, index) =>
index === 2 ? item * 10 : item
)
// ✅ 对象不可变操作
const originalObject = { name: '阿超', age: 28, city: '北京' }
// 添加/更新属性
const withNewProp = { ...originalObject, email: 'achao@example.com' }
const withUpdatedAge = { ...originalObject, age: 29 }
// 删除属性
const { city, ...withoutCity } = originalObject
// 嵌套更新
const user = {
name: '阿超',
profile: { avatar: 'old.jpg', bio: '程序员' }
}
const updatedUser = {
...user,
profile: {
...user.profile,
avatar: 'new.jpg'
}
}
🛡️ 错误处理
1. 自定义错误类
javascript
class APIError extends Error {
constructor(message, status, code) {
super(message)
this.name = 'APIError'
this.status = status
this.code = code
}
}
class ValidationError extends Error {
constructor(message, field) {
super(message)
this.name = 'ValidationError'
this.field = field
}
}
// 使用示例
async function fetchUser(id) {
if (!id) {
throw new ValidationError('用户ID不能为空', 'id')
}
try {
const response = await fetch(`/api/users/${id}`)
if (!response.ok) {
throw new APIError(
'获取用户失败',
response.status,
'USER_FETCH_FAILED'
)
}
return await response.json()
} catch (error) {
if (error instanceof APIError || error instanceof ValidationError) {
throw error
}
throw new Error('未知错误')
}
}
2. 全局错误处理
javascript
// 全局未捕获错误处理
window.addEventListener('error', (event) => {
console.error('全局错误:', event.error)
// 发送错误报告到服务器
reportError(event.error)
})
// Promise 未捕获错误处理
window.addEventListener('unhandledrejection', (event) => {
console.error('未处理的Promise拒绝:', event.reason)
event.preventDefault() // 阻止默认的错误处理
reportError(event.reason)
})
function reportError(error) {
// 发送错误信息到监控服务
fetch('/api/errors', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
message: error.message,
stack: error.stack,
url: window.location.href,
timestamp: new Date().toISOString()
})
}).catch(console.error)
}
📝 总结
这些JavaScript技巧和最佳实践可以帮助你:
- 🚀 编写更简洁、高效的代码
- 🛡️ 提高代码的健壮性和可维护性
- 🎯 掌握现代JavaScript的核心特性
- 💡 培养函数式编程思维
记住,好的代码不仅要能运行,还要易读、易维护、易扩展。持续学习和实践是提升JavaScript技能的关键!
希望这些技巧对你的JavaScript开发有所帮助! 🎉