Skip to content

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开发有所帮助! 🎉

Last updated: