1
0
0
20个必知的JavaScript高级用法,让你的代码脱胎换骨
文章摘要
|
JavaScript 是前端开发的核心语言,但大多数人只用了它 20% 的功能。这篇文章整理了 20 个实战中高频使用的 JS 技巧和用法,每一个都配了详细的代码示例,建议收藏慢慢看。
一、数组的 7 个高阶用法
1. reduce 实现数据转换和聚合
reduce 不只是用来求和的,它几乎可以实现任何数组转换操作。
// 基础:求和
const sum = [1, 2, 3, 4].reduce((acc, cur) => acc + cur, 0) // 10
// 用法1:数组转对象(按字段分组)
const users = [
{ name: '张三', role: 'admin' },
{ name: '李四', role: 'user' },
{ name: '王五', role: 'admin' },
{ name: '赵六', role: 'user' }
]
const grouped = users.reduce((acc, cur) => {
const key = cur.role
if (!acc[key]) acc[key] = []
acc[key].push(cur)
return acc
}, {})
// { admin: [{name:'张三'...}, {name:'王五'...}], user: [{name:'李四'...}, {name:'赵六'...}] }
// 用法2:数组去重
const duplicates = [1, 2, 2, 3, 4, 4, 5]
const unique = duplicates.reduce((acc, cur) => {
if (!acc.includes(cur)) acc.push(cur)
return acc
}, []) // [1, 2, 3, 4, 5]
// 用法3:统计元素出现次数
const fruits = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']
const count = fruits.reduce((acc, cur) => {
acc[cur] = (acc[cur] || 0) + 1
return acc
}, {}) // { apple: 3, banana: 2, orange: 1 }
// 用法4:管道函数(链式数据处理)
const pipe = (...fns) => (initial) => fns.reduce((acc, fn) => fn(acc), initial)
const addOne = x => x + 1
const double = x => x * 2
const square = x => x * x
const process = pipe(addOne, double, square)
process(3) // ((3+1)*2)^2 = 642. flat 和 flatMap 处理嵌套数据
// 摊平嵌套数组
const nested = [1, [2, 3], [4, [5, [6, 7]]]]
nested.flat(1) // [1, 2, 3, 4, [5, [6, 7]]]
nested.flat(2) // [1, 2, 3, 4, 5, [6, 7]]
nested.flat(Infinity) // [1, 2, 3, 4, 5, 6, 7] 完全摊平
// flatMap:map + flat 一步到位
const sentences = ['hello world', 'goodbye world']
sentences.flatMap(s => s.split(' ')) // ['hello', 'world', 'goodbye', 'world']
// 实用场景:过滤空值并处理
const data = [1, null, 2, undefined, 3, '', 4]
data.flatMap(item => item ? [item * 2] : []) // [2, 4, 6, 8]
// 场景:从数组中提取嵌套属性
const posts = [
{ id: 1, tags: ['js', 'react'] },
{ id: 2, tags: ['vue', 'js'] },
{ id: 3, tags: ['angular'] }
]
const allTags = posts.flatMap(p => p.tags) // ['js', 'react', 'vue', 'js', 'angular']
// 顺便去重
const uniqueTags = [...new Set(allTags)] // ['js', 'react', 'vue', 'angular']3. find / findIndex / findLast / findLastIndex
const users = [
{ id: 1, name: '张三', age: 25, active: false },
{ id: 2, name: '李四', age: 30, active: true },
{ id: 3, name: '王五', age: 22, active: true },
{ id: 4, name: '赵六', age: 28, active: false }
]
// 找到第一个符合条件的
users.find(u => u.active) // { id:2, name:'李四', age:30, active:true }
users.findIndex(u => u.id === 3) // 2
// 从后往前找
users.findLast(u => u.active) // { id:3, name:'王五', age:22, active:true }
users.findLastIndex(u => u.active) // 2
// 按条件查找
const adult = users.find(u => u.age >= 30) // 李四
const firstActive = users.find(u => u.active && u.age < 25) // 王五4. some / every / includes 条件判断
const ages = [12, 18, 22, 30]
// some:至少一个满足条件
ages.some(age => age < 18) // true
// 等价于:ages.filter(age => age < 18).length > 0
// every:全部满足条件
ages.every(age => age >= 18) // false
// includes:是否存在该元素(简单类型)
const colors = ['red', 'blue', 'green']
colors.includes('blue') // true
// 复杂类型要慎用 includes(比较引用)
const objArr = [{ id: 1 }, { id: 2 }]
objArr.includes({ id: 1 }) // false ❌ 不同引用
// 复杂类型用 some
objArr.some(item => item.id === 1) // true ✅
// 应用:权限检查
const userPermissions = ['read', 'write']
const required = ['read', 'write', 'delete']
const hasAll = required.every(p => userPermissions.includes(p)) // false
// 应用:表单验证
const form = { name: '', email: 'test@example.com', age: 0 }
const hasEmptyField = Object.values(form).some(v => !v) // true5. reduceRight:从右到左的聚合
// 从右到左执行 reduce
const arr = ['a', 'b', 'c', 'd']
arr.reduce((acc, cur) => acc + cur) // 'abcd'
arr.reduceRight((acc, cur) => acc + cur) // 'dcba'
// 应用:嵌套函数的执行顺序控制
const functions = [
x => x + 1,
x => x * 2,
x => x - 3
]
// 从右到左执行:先减3,再乘2,再加1
const result = functions.reduceRight((acc, fn) => fn(acc), 10) // (10-3)*2+1 = 15
// 应用:右折叠构建嵌套结构
const nested = ['a', 'b', 'c'].reduceRight((acc, cur) => ({ [cur]: acc }), {})
// { a: { b: { c: {} } } }6. 数组解构的 6 种高级姿势
// 1. 交换变量
let a = 1, b = 2
[a, b] = [b, a] // a=2, b=1
// 2. 跳过元素
const [first, , third] = [1, 2, 3, 4] // first=1, third=3
// 3. 剩余元素(rest)
const [head, ...tail] = [1, 2, 3, 4] // head=1, tail=[2,3,4]
// 4. 默认值
const [x = 0, y = 0] = [5] // x=5, y=0
// 5. 嵌套解构
const matrix = [[1, 2], [3, 4]]
const [[one, two], [three, four]] = matrix
// 6. 函数参数解构
function sum([a, b]) { return a + b }
sum([3, 5]) // 8
function getCoords({ x, y }) { return `(${x}, ${y})` }
getCoords({ x: 10, y: 20 }) // '(10, 20)'7. 数组方法链式调用
const orders = [
{ id: 1, amount: 100, status: 'paid' },
{ id: 2, amount: 50, status: 'pending' },
{ id: 3, amount: 200, status: 'paid' },
{ id: 4, amount: 75, status: 'shipped' },
{ id: 5, amount: 150, status: 'paid' }
]
// 链式处理:筛选已支付订单 → 提取金额 → 大于100的 → 求和
const total = orders
.filter(o => o.status === 'paid') // 只保留已支付
.map(o => o.amount) // 提取金额
.filter(amount => amount > 100) // 只保留大于100的
.reduce((sum, amount) => sum + amount, 0) // 求和
// 结果:200 + 150 = 350
// 实际项目中的链式数据转换
const transformedData = rawData
.filter(item => item.isValid)
.sort((a, b) => a.order - b.order)
.slice(0, 10) // 取前10条
.map(item => ({
...item,
displayName: `${item.firstName} ${item.lastName}`,
createdAt: new Date(item.createdAt).toLocaleDateString()
}))二、对象的 4 个高级用法
8. 对象解构与重命名
const user = { id: 1, name: '张三', age: 25, email: 'zhangsan@example.com' }
// 基础解构
const { name, age } = user
// 重命名
const { name: userName, email: userEmail } = user
// 默认值 + 重命名
const { phone: userPhone = '未填写' } = user
// 剩余属性
const { id, ...rest } = user // rest = { name:'张三', age:25, email:'...' }
// 深层解构
const response = {
code: 200,
data: {
user: { id: 1, profile: { nickname: '小张' } }
}
}
const { data: { user: { profile: { nickname } } } } = response // '小张'
// 函数参数解构 + 默认值
function createUser({ name, age = 18, email = 'default@example.com' }) {
return { name, age, email }
}
createUser({ name: '李四' }) // { name:'李四', age:18, email:'default@example.com' }9. 对象属性名动态计算
// 动态 key
const key = 'dynamicKey'
const obj = {
staticKey: '静态值',
[key]: '动态值'
}
// { staticKey:'静态值', dynamicKey:'动态值' }
// 结合表达式
const prefix = 'user_'
const id = 123
const userObj = {
[`${prefix}${id}`]: '张三'
}
// { user_123: '张三' }
// 实际应用:根据条件构建对象
const action = 'edit'
const actions = {
add: () => console.log('新增'),
edit: () => console.log('编辑'),
delete: () => console.log('删除')
}
actions[action]() // '编辑'
// 应用:动态设置表单字段
function updateField(field, value) {
setState(prev => ({
...prev,
[field]: value
}))
}10. 对象的浅拷贝与深拷贝
// 浅拷贝
const original = { a: 1, b: { c: 2 } }
// 方法1:展开运算符(推荐)
const copy1 = { ...original }
// 方法2:Object.assign
const copy2 = Object.assign({}, original)
// 方法3:Object.create(原型链拷贝)
const copy3 = Object.create(original)
// 浅拷贝的坑:b 还是同一个引用
copy1.b.c = 3
console.log(original.b.c) // 3 ❌ 原对象也被改了
// 深拷贝方法
const deep = { a: 1, b: { c: 2 } }
// 方法1:JSON(但无法处理函数、undefined、循环引用)
const deepCopy1 = JSON.parse(JSON.stringify(deep))
// 方法2:structuredClone(现代浏览器,推荐)
const deepCopy2 = structuredClone(deep)
// 方法3:递归实现(手写)
function deepClone(obj, hash = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj
if (hash.has(obj)) return hash.get(obj)
const clone = Array.isArray(obj) ? [] : {}
hash.set(obj, clone)
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
clone[key] = deepClone(obj[key], hash)
}
}
return clone
}
// 方法4:使用 lodash(生产环境推荐)
// import cloneDeep from 'lodash/cloneDeep'
// const deepCopy3 = cloneDeep(deep)11. Object 的静态方法合集
const obj = { a: 1, b: 2, c: 3 }
// 获取 key 数组
Object.keys(obj) // ['a', 'b', 'c']
// 获取 value 数组
Object.values(obj) // [1, 2, 3]
// 获取 entries 数组
Object.entries(obj) // [['a',1], ['b',2], ['c',3]]
// entries 转对象
const entries = [['a', 1], ['b', 2]]
Object.fromEntries(entries) // { a:1, b:2 }
// 实际应用:过滤对象属性
const user = { id: 1, name: '张三', password: '123456', age: 25 }
const { password, ...safeUser } = user // 移除敏感字段
// 或者用 entries 过滤
const filtered = Object.fromEntries(
Object.entries(user).filter(([key]) => key !== 'password')
)
// 应用:对象遍历并转换
const doubled = Object.fromEntries(
Object.entries(obj).map(([key, value]) => [key, value * 2])
) // { a:2, b:4, c:6 }
// 应用:合并多个对象
const merged = Object.assign({}, obj1, obj2, obj3)
// 或使用展开
const merged2 = { ...obj1, ...obj2, ...obj3 }三、函数的 4 个高级用法
12. 闭包与私有变量
// 1. 创建私有变量
function createCounter() {
let count = 0 // 私有变量,外部无法直接访问
return {
increment() { count++; return count },
decrement() { count--; return count },
getCount() { return count },
reset() { count = 0 }
}
}
const counter = createCounter()
counter.increment() // 1
counter.increment() // 2
counter.getCount() // 2
// counter.count // undefined ❌ 无法直接访问
// 2. 柯里化(闭包应用)
function add(x) {
return function(y) {
return x + y
}
}
const add5 = add(5)
add5(3) // 8
add5(10) // 15
// 3. 闭包与循环(经典陷阱及解决)
// ❌ 错误写法
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100) // 输出 3,3,3
}
// ✅ 用 let 解决
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100) // 输出 0,1,2
}
// ✅ 用闭包解决(var 场景)
for (var i = 0; i < 3; i++) {
(function(j) {
setTimeout(() => console.log(j), 100)
})(i) // 输出 0,1,2
}13. 高阶函数与函数组合
// 1. 函数组合
const compose = (...fns) => (x) => fns.reduceRight((acc, fn) => fn(acc), x)
const pipe = (...fns) => (x) => fns.reduce((acc, fn) => fn(acc), x)
// 2. 防抖(Debounce)
function debounce(fn, delay = 300) {
let timer = null
return function(...args) {
clearTimeout(timer)
timer = setTimeout(() => fn.apply(this, args), delay)
}
}
// 使用:搜索输入
const searchHandler = debounce((keyword) => {
console.log('搜索:', keyword)
// 调用 API
}, 500)
// 3. 节流(Throttle)
function throttle(fn, interval = 300) {
let lastTime = 0
return function(...args) {
const now = Date.now()
if (now - lastTime >= interval) {
lastTime = now
fn.apply(this, args)
}
}
}
// 使用:滚动事件
const scrollHandler = throttle(() => {
console.log('滚动位置:', window.scrollY)
}, 200)
// 4. once:只执行一次的函数
function once(fn) {
let executed = false
return function(...args) {
if (!executed) {
executed = true
return fn.apply(this, args)
}
}
}
const init = once(() => console.log('初始化完成'))
init() // '初始化完成'
init() // 不执行14. 函数式编程常用工具
// 1. memoize:缓存函数结果
function memoize(fn) {
const cache = new Map()
return function(...args) {
const key = JSON.stringify(args)
if (cache.has(key)) return cache.get(key)
const result = fn.apply(this, args)
cache.set(key, result)
return result
}
}
const expensiveFn = (n) => {
console.log('计算中...')
return n * n
}
const memoizedFn = memoize(expensiveFn)
memoizedFn(5) // '计算中...' 25
memoizedFn(5) // 25(直接返回缓存结果)
// 2. partial:偏函数(固定部分参数)
function partial(fn, ...fixedArgs) {
return function(...remainingArgs) {
return fn(...fixedArgs, ...remainingArgs)
}
}
const multiply = (a, b, c) => a * b * c
const multiplyBy2 = partial(multiply, 2)
multiplyBy2(3, 4) // 2*3*4 = 24
// 3. curry:柯里化通用实现
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args)
}
return function(...moreArgs) {
return curried.apply(this, [...args, ...moreArgs])
}
}
}
const sum = (a, b, c) => a + b + c
const curriedSum = curry(sum)
curriedSum(1)(2)(3) // 6
curriedSum(1, 2)(3) // 6
curriedSum(1)(2, 3) // 615. 回调函数与异步控制
// 1. 回调转 Promise
function promisify(fn) {
return function(...args) {
return new Promise((resolve, reject) => {
fn(...args, (err, result) => {
if (err) reject(err)
else resolve(result)
})
})
}
}
// 使用:将 Node.js 风格的 fs.readFile 转换为 Promise
// const readFilePromise = promisify(fs.readFile)
// 2. 并行执行(Promise.all vs Promise.allSettled)
const p1 = Promise.resolve(1)
const p2 = Promise.reject('error')
const p3 = Promise.resolve(3)
// all:一个失败全部失败
Promise.all([p1, p2, p3])
.then(results => console.log(results))
.catch(err => console.log('错误:', err)) // '错误:error'
// allSettled:全部完成,收集结果
Promise.allSettled([p1, p2, p3])
.then(results => {
results.forEach(r => {
if (r.status === 'fulfilled') console.log('成功:', r.value)
else console.log('失败:', r.reason)
})
})
// 3. 串行执行
async function runSerial(tasks) {
const results = []
for (const task of tasks) {
results.push(await task())
}
return results
}
// 4. 限流并发(控制并发数量)
async function asyncPool(limit, tasks) {
const results = []
const executing = []
for (const [index, task] of tasks.entries()) {
const p = Promise.resolve().then(() => task())
results[index] = p
if (limit <= tasks.length) {
const e = p.then(() => executing.splice(executing.indexOf(e), 1))
executing.push(e)
if (executing.length >= limit) {
await Promise.race(executing)
}
}
}
return Promise.all(results)
}
// 使用:同时最多5个请求
// const result = await asyncPool(5, urls.map(url => () => fetch(url)))四、字符串的 2 个高级用法
16. 模板字符串的高级技巧
// 1. 多行字符串
const multiline = `
第一行
第二行
第三行
`
// 2. 表达式嵌入
const name = '张三'
const age = 25
const msg = `我叫${name},今年${age}岁,明年${age + 1}岁`
// 3. 标签模板(Tagged Template)
function highlight(strings, ...values) {
return strings.reduce((acc, str, i) => {
return acc + str + (values[i] ? `<strong>${values[i]}</strong>` : '')
}, '')
}
const user = '张三'
const action = '登录'
const result = highlight`用户 ${user} 刚刚 ${action} 了系统`
// 输出:用户 <strong>张三</strong> 刚刚 <strong>登录</strong> 了系统
// 4. 模板字符串的嵌套
const items = ['苹果', '香蕉', '橘子']
const list = `
<ul>
${items.map(item => ` <li>${item}</li>`).join('')}
</ul>
`
// 5. 条件渲染
const isAdmin = true
const template = `
<div>
${isAdmin ? `<button>管理</button>` : ''}
</div>
`17. 字符串的实用方法合集
// 1. 字符串填充
'5'.padStart(3, '0') // '005'
'5'.padEnd(3, '0') // '500'
'12'.padStart(4, '0') // '0012'
// 应用:生成固定长度的编号
const orderNo = 'ORDER-' + String(123).padStart(6, '0') // 'ORDER-000123'
// 2. 去除空白
' hello '.trim() // 'hello'
' hello '.trimStart() // 'hello '
' hello '.trimEnd() // ' hello'
// 3. 判断开头/结尾
'hello.js'.startsWith('hello') // true
'hello.js'.endsWith('.js') // true
// 应用:文件类型判断
function isImage(filename) {
return /\.(jpg|jpeg|png|gif|webp)$/i.test(filename)
}
// 4. 重复字符串
'*'.repeat(10) // '**********'
// 应用:生成分隔线
console.log('='.repeat(50))
// 5. replaceAll(全部替换)
'hello world hello'.replaceAll('hello', 'hi') // 'hi world hi'
// 以前用正则:'hello world hello'.replace(/hello/g, 'hi')
// 6. 分割并保留分隔符
const parts = 'a,b,c'.split(/(,)/) // ['a', ',', 'b', ',', 'c']
// 7. 截取与提取
'hello world'.slice(0, 5) // 'hello'
'hello world'.substring(6, 11) // 'world'
'hello world'.substr(6, 5) // 'world'(已废弃,建议用slice)五、数字与数学的 2 个用法
18. 数字处理技巧
javascript
// 1. 安全的整数运算(BigInt)
const big = 9007199254740991n
const big2 = BigInt('9007199254740992')
big + big2 // 18014398509481983n
// 2. 格式化数字
const num = 12345.6789
num.toFixed(2) // '12345.68'
num.toLocaleString() // '12,345.679'
num.toLocaleString('zh-CN', { style: 'currency', currency: 'CNY' }) // '¥12,345.68'
// 3. 精度处理
function roundTo(n, precision = 2) {
const factor = Math.pow(10, precision)
return Math.round(n * factor) / factor
}
roundTo(1.23456, 2) // 1.23
// 4. 随机数
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min
}
randomInt(1, 100) // 1-100之间的随机整数
// 5. 数字范围判断
const isBetween = (n, min, max) => n >= min && n <= max
isBetween(5, 1, 10) // true
// 6. 安全的除法
function safeDiv(a, b, defaultValue = 0) {
return b === 0 ? defaultValue : a / b
}19. Math 对象的实用方法
// 1. 取整
Math.floor(3.7) // 3(向下取整)
Math.ceil(3.2) // 4(向上取整)
Math.round(3.5) // 4(四舍五入)
Math.trunc(3.7) // 3(去除小数部分)
// 2. 最大/最小值
Math.max(1, 3, 2) // 3
Math.min(1, 3, 2) // 1
// 数组中的最大/最小
const arr = [1, 5, 3, 9, 2]
Math.max(...arr) // 9
Math.min(...arr) // 1
// 3. 幂运算
Math.pow(2, 10) // 1024
2 ** 10 // 1024(ES7指数运算符)
// 4. 平方根
Math.sqrt(16) // 4
// 5. 绝对值
Math.abs(-5) // 5
// 6. 三角函数
Math.sin(Math.PI / 2) // 1
Math.cos(0) // 1
// 7. 对数
Math.log(Math.E) // 1
// 实际应用:计算两点距离
function distance(x1, y1, x2, y2) {
return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2))
}
distance(0, 0, 3, 4) // 5六、集合的 1 个用法
20. Set 和 Map 的高级用法
// ===== Set =====
// 1. 数组去重(最常用)
const arr = [1, 2, 2, 3, 4, 4, 5]
const uniqueArr = [...new Set(arr)] // [1, 2, 3, 4, 5]
// 2. 字符串去重
const str = 'aabbccddeeff'
const uniqueStr = [...new Set(str)].join('') // 'abcdef'
// 3. 集合运算
const setA = new Set([1, 2, 3, 4])
const setB = new Set([3, 4, 5, 6])
// 并集
const union = new Set([...setA, ...setB]) // {1,2,3,4,5,6}
// 交集
const intersection = new Set([...setA].filter(x => setB.has(x))) // {3,4}
// 差集(A - B)
const difference = new Set([...setA].filter(x => !setB.has(x))) // {1,2}
// 对称差集(A⊕B)
const symmetricDiff = new Set([
...[...setA].filter(x => !setB.has(x)),
...[...setB].filter(x => !setA.has(x))
]) // {1,2,5,6}
// ===== Map =====
// 1. Map 与 Object 的区别:key 可以是任意类型
const map = new Map()
map.set('string', '值1')
map.set(1, '值2')
map.set({ key: 'obj' }, '值3') // 对象作为 key
// 2. 链式操作
const userMap = new Map()
.set('张三', { age: 25, role: 'admin' })
.set('李四', { age: 30, role: 'user' })
// 3. 遍历 Map
for (const [key, value] of userMap) {
console.log(`${key}:`, value)
}
userMap.forEach((value, key) => console.log(key, value))
// 4. Map ↔ Object 互转
const obj = { a: 1, b: 2 }
const mapFromObj = new Map(Object.entries(obj)) // Map { 'a' => 1, 'b' => 2 }
const objFromMap = Object.fromEntries(mapFromObj) // { a:1, b:2 }
// 5. Map 用于缓存
const cache = new Map()
function getData(id) {
if (cache.has(id)) return cache.get(id)
const data = fetchData(id) // 假设是耗时的操作
cache.set(id, data)
return data
}
// 6. WeakMap(弱引用,key 必须是对象)
const weakMap = new WeakMap()
const keyObj = { id: 1 }
weakMap.set(keyObj, '关联的值')
// 当 keyObj 没有其他引用时,会自动被垃圾回收七、总结
这 20 个用法覆盖了数组、对象、函数、字符串、数字、集合等 JavaScript 核心领域,每一个都是实战中高频使用的技巧。
建议你不要一次性全部看完,而是收藏起来,遇到相关问题的时候翻出来对照使用。用多了自然就记住了,代码质量也会肉眼可见地提升。
如果你觉得有用,欢迎点赞、转发、收藏,让更多前端小伙伴看到!🚀

