2024-2025 JavaScript 最新语法糖:这10个新特性,让你的代码优雅到同事看不懂
JavaScript 每年都在进化,TC39 每年都会推送一些让代码更简洁、更易读的新特性。本文整理 2024-2025 年最值得掌握的 10 个新语法,从 ES2022 到 ES2025,带你感受什么叫"原来 JS 也可以这么优雅"。
一、ES2022 早已落地,但你可能还没用
1. # приватные поля — 真正的私有属性
之前我们用 _name 下划线约定来"假装"私有,但 JavaScript 给了我们真正的私有字段。
老写法:
class User {
constructor(name, password) {
this.name = name
this._password = password // 这只是约定,谁都能访问
}
getPassword() {
return this._password
}
}
新写法:
class User {
#password // 真私有,外部无法访问
#token
constructor(name, password) {
this.name = name
this.#password = password
}
validate(input) {
return this.#checkPassword(input) // 类内部任意方法都能访问
}
#checkPassword(input) { // 私有方法也一样
return input === this.#password
}
}
const u = new User('张三', '123456')
u.name // ✅ '张三'
u.#password // ❌ SyntaxError: Private field '#password' must be declared
好处: 编译期就报错,不是运行时才暴露,数据封装从"约定"变成"强制"。
2. .at() — 终于可以优雅地取倒数第N个
老写法:
const arr = [1, 2, 3, 4, 5]
arr[arr.length - 1] // 5,要写这么长...
arr[arr.length - 2] // 4,痛苦
新写法:
const arr = [1, 2, 3, 4, 5]
arr.at(-1) // 5 ✅
arr.at(-2) // 4 ✅
// 字符串也行
'hello'.at(-1) // 'o'
好处: 代码意图清晰,不再需要 length - 1 这种绕弯子的写法。
3. Object.hasOwn() — 比 in 更安全的属性检测
老写法:
const obj = { a: 1 }
// ❌ 陷阱:in 会遍历原型链,可能误判
console.log('constructor' in obj) // true(来自原型链!)
// ✅ 正确但冗长
console.log(Object.prototype.hasOwnProperty.call(obj, 'a')) // true
新写法:
const obj = { a: 1 }
console.log(Object.hasOwn(obj, 'a')) // true
console.log(Object.hasOwn(obj, 'constructor')) // false ✅,不误判原型链
好处: 更简洁,更安全,不用记那个超长的 hasOwnProperty.call。
4. error.cause — 错误链追踪,终于不用手动传参了
老写法:
function fetchData() {
try {
JSON.parse('invalid json')
} catch (e) {
// 手动包装,繁琐
throw new Error('获取数据失败', { cause: e })
}
}
新写法:
function fetchData() {
try {
JSON.parse('invalid json')
} catch (e) {
// 第三参数直接指定 cause,自动传递
throw new Error('获取数据失败', { cause: e })
}
}
try {
fetchData()
} catch (e) {
console.log(e.cause) // SyntaxError: Unexpected token...
console.log(e.cause.message) // 直接拿到原始错误信息
}
二、ES2023 — 小但实用的改进
5. 数组的 .toSorted()、.toReversed()、.toSpliced() — 不修改原数组
老写法:
const nums = [3, 1, 4, 1, 5]
nums.sort() // 修改了原数组!
nums.reverse() // 又修改了!
新写法:
const nums = [3, 1, 4, 1, 5]
const sorted = nums.toSorted() // 返回新数组,原数组不变 ✅
const reversed = nums.toReversed() // 返回新数组,原数组不变 ✅
const spliced = nums.toSpliced(1, 2) // 同理,返回新数组
console.log(nums) // [3, 1, 4, 1, 5] 完好无损
console.log(sorted) // [1, 1, 3, 4, 5]
好处: 再也不用 concat([...nums]) 这种 hack 写法了,代码意图一目了然。
6. hash 式的 WeakMap / WeakSet — 手动 GC 控制
// 新的 Symbol key 版本,让 WeakMap/WeakSet 更实用
const cache = new WeakMap()
const obj = { id: 1 }
cache.set(obj, 'cached result')
// 不再只能用对象作为 key 了
const map = new WeakMap()
map.set(123, 'number key') // ✅ ES2023 支持基本类型作为 WeakMap key
三、ES2024 — 让人眼前一亮的重磅功能
7. Array.prototype.groupBy — 数据分组的利器
老写法:
const products = [
{ name: '手机', category: '数码', price: 3000 },
{ name: 'T恤', category: '服装', price: 200 },
{ name: '电脑', category: '数码', price: 8000 },
{ name: '裤子', category: '服装', price: 150 },
]
// 写一个 reduce 来分组
const grouped = products.reduce((acc, item) => {
if (!acc[item.category]) acc[item.category] = []
acc[item.category].push(item)
return acc
}, {})
// 结果:{ '数码': [...], '服装': [...] }
新写法:
const products = [
{ name: '手机', category: '数码', price: 3000 },
{ name: 'T恤', category: '服装', price: 200 },
{ name: '电脑', category: '数码', price: 8000 },
{ name: '裤子', category: '服装', price: 150 },
]
// 一行搞定!
const grouped = Object.groupBy(products, item => item.category)
const priceMap = Object.groupBy(products, item => item.price > 1000 ? 'expensive' : 'cheap')
console.log(grouped)
// {
// '数码': [{ name: '手机', ... }, { name: '电脑', ... }],
// '服装': [{ name: 'T恤', ... }, { name: '裤子', ... }]
// }
好处: 数据处理代码从 5-6 行变成 1 行,可读性大幅提升。
8. 正则表达式的 v flag — Unicode 模式升级
// 以前:处理 emoji 和复杂 Unicode 字符会出问题
/^\p{Emoji}/.test('👋') // ❌ 报错,需要 u flag
// v flag:更好的 Unicode 字符类处理
/^\p{RGI_Emoji}$/v.test('👋') // ✅
/^\p{Script=Han}+$/v.test('你好世界') // ✅ 判断是否全是汉字
// 集合运算,之前的 u flag 做不到
/^[\p{ASCII}&&[\p{Emoji}]]+$/v.test('😀') // false,只有 emoji 才是 emoji
四、ES2025 — 前沿预览,已经可以在 Node 22/Bun 中使用
9. Promise.withResolvers() — 告别 new Promise 的样板代码
老写法:
function fetchSomething() {
let resolve, reject
const promise = new Promise((res, rej) => {
resolve = res
reject = rej
})
setTimeout(() => resolve('data'), 1000)
return { promise, resolve, reject }
}
新写法:
function fetchSomething() {
const { promise, resolve, reject } = Promise.withResolvers()
setTimeout(() => resolve('data'), 1000)
return { promise, resolve, reject }
}
// 或者更简洁的场景
async function loadConfig() {
const { promise, resolve } = Promise.withResolvers()
window.addEventListener('config-loaded', () => resolve(), { once: true })
return promise
}
好处: 省去 5 行样板代码,语义更清晰。
10. Array.prototype.findLast() — 从后往前找
const scores = [85, 92, 73, 88, 95, 78]
scores.find(n => n > 80) // 92(从前往后找第一个)
scores.findLast(n => n > 80) // 95(从后往前找第一个)✅
// 之前要这么写:
[...scores].reverse().find(n => n > 80) // 先 reverse,太蠢了
五、TypeScript 独享的语法糖(但你应该在用)
装饰器(正式稳定)
// TypeScript 5.x+,装饰器正式稳定
function log(target: any, key: string, descriptor: PropertyDescriptor) {
const original = descriptor.value
descriptor.value = function (...args: any[]) {
console.log(`调用 ${key},参数:`, args)
return original.apply(this, args)
}
return descriptor
}
class Calculator {
@log
add(a: number, b: number) {
return a + b
}
}
const calc = new Calculator()
calc.add(1, 2) // 输出:调用 add,参数: [1, 2]
// 返回: 3
总结:这些语法糖的实际价值
| 特性 | 核心价值 | 日常可用性 |
|---|---|---|
#私有字段 | 真正的封装 | ✅ 立刻用 |
.at() | 代码简洁 | ✅ 立刻用 |
Object.hasOwn() | 更安全的检测 | ✅ 立刻用 |
.toSorted() 系列 | 不破坏原数据 | ✅ 立刻用 |
groupBy | 一行分组 | ✅ 立刻用 |
Promise.withResolvers() | 减少样板代码 | ✅ 立刻用 |
findLast() | 更直观的数据查找 | ✅ 立刻用 |
正则 v flag | 处理 emoji/Unicode | ⚠️ 逐步迁移 |
| 装饰器 | AOP 编程 | ⚠️ TS 项目可用 |
这些新特性有一个共同点:不是为了炫技,而是让代码意图更清晰、bug 更少。
能用新语法就用新语法,现代 Node 22 和 Chrome 122+ 已经完全支持以上所有特性。
如果这篇文章有帮助,欢迎点赞收藏。你的项目里用上了几个新特性?评论区见~