2024-2025 JavaScript 最新语法糖:这10个新特性,让你的代码优雅到同事看不懂

47 阅读1分钟

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+ 已经完全支持以上所有特性。


如果这篇文章有帮助,欢迎点赞收藏。你的项目里用上了几个新特性?评论区见~