JavaScript未来

JavaScript 是一门不断发展的语言,每年都会添加新特性。了解语言的发展方向,能帮助你更好地规划学习路径和项目技术选型。

ECMAScript 标准

标准化流程

阶段 名称 说明
Stage 0 Strawman 提案想法
Stage 1 Proposal 正式提案
Stage 2 Draft 草案规范
Stage 3 Candidate 候选推荐
Stage 4 Finished 等待发布

版本历史

版本 年份 重要特性
ES5 2009 严格模式、JSON、Object 方法
ES6/ES2015 2015 let/const、箭头函数、类、模块、Promise
ES2016 2016 includes、指数运算符
ES2017 2017 async/await、Object.entries
ES2018 2018 对象展开、异步迭代
ES2019 2019 flat、fromEntries、可选 catch
ES2020 2020 可选链、空值合并、BigInt
ES2021 2021 逻辑赋值、replaceAll、数字分隔符
ES2022 2022 顶层 await、类私有字段、at()
ES2023 2023 从后查找、Symbols 作为 WeakMap 键
ES2024 2024 数组分组、Promise.withResolvers

ES2022+ 新特性

顶层 await

// ES2022 之前:必须在 async 函数内
async function main() {
  const data = await fetch('/api/data')
  return data
}

// ES2022:顶层 await
const response = await fetch('/api/data')
const data = await response.json()

console.log(data)

// 条件加载模块
const config = await (
  process.env.NODE_ENV === 'production' 
    ? import('./config.prod.js')
    : import('./config.dev.js')
)

类私有字段

class User {
  // 私有字段
  #name
  #age
  
  constructor(name, age) {
    this.#name = name
    this.#age = age
  }
  
  // 私有方法
  #validate() {
    return this.#age > 0
  }
  
  // 公共方法访问私有字段
  getName() {
    return this.#name
  }
  
  // 静态私有字段
  static #count = 0
  
  static getCount() {
    return User.#count
  }
}

const user = new User('东巴文', 18)
console.log(user.getName())  // 东巴文
// console.log(user.#name)   // 语法错误

类静态块

class Config {
  static instance
  static version = '1.0.0'
  
  // 静态初始化块
  static {
    try {
      this.instance = new Config()
      console.log('配置初始化完成')
    } catch (e) {
      console.error('初始化失败', e)
    }
  }
  
  constructor() {
    // 实例初始化
  }
}

数组 at() 方法

const arr = ['东', '巴', '文', '教', '程']

// 之前:获取最后一个元素
arr[arr.length - 1]  // 程

// 现在:使用 at()
arr.at(-1)   // 程
arr.at(-2)   // 教
arr.at(0)    // 东

// 字符串也支持
'东巴文'.at(-1)  // 文

Object.hasOwn()

const user = { name: '东巴文' }

// 之前
Object.prototype.hasOwnProperty.call(user, 'name')  // true

// 现在
Object.hasOwn(user, 'name')  // true
Object.hasOwn(user, 'age')   // false

// 更安全:不依赖原型链
const obj = Object.create(null)
obj.name = '东巴文'
// obj.hasOwnProperty('name')  // 错误:没有继承 hasOwnProperty
Object.hasOwn(obj, 'name')     // true

Error Cause

async function fetchUser(id) {
  try {
    const response = await fetch(`/api/users/${id}`)
    return response.json()
  } catch (error) {
    throw new Error(`获取用户 ${id} 失败`, { cause: error })
  }
}

try {
  await fetchUser(1)
} catch (error) {
  console.error(error.message)
  console.error(error.cause)  // 原始错误
}

ES2023 新特性

数组从后查找

const arr = [1, 2, 3, 4, 5, 4, 3, 2, 1]

// 从后查找
arr.findLast(x => x > 3)      // 4
arr.findLastIndex(x => x > 3) // 5

// 对比从前查找
arr.find(x => x > 3)          // 4
arr.findIndex(x => x > 3)     // 3

数组分组

const users = [
  { name: '东巴文', role: 'admin' },
  { name: '用户A', role: 'user' },
  { name: '用户B', role: 'user' },
  { name: '用户C', role: 'guest' }
]

// Object.groupBy
const byRole = Object.groupBy(users, user => user.role)
// {
//   admin: [{ name: '东巴文', role: 'admin' }],
//   user: [{ name: '用户A', role: 'user' }, { name: '用户B', role: 'user' }],
//   guest: [{ name: '用户C', role: 'guest' }]
// }

// Map.groupBy
const byRoleMap = Map.groupBy(users, user => user.role)

数组不修改原数组的方法

const arr = [3, 1, 4, 1, 5, 9]

// toSorted:返回新数组
const sorted = arr.toSorted()
console.log(arr)     // [3, 1, 4, 1, 5, 9] 原数组不变
console.log(sorted)  // [1, 1, 3, 4, 5, 9]

// toReversed
const reversed = arr.toReversed()
console.log(arr)       // [3, 1, 4, 1, 5, 9]
console.log(reversed)  // [9, 5, 1, 4, 1, 3]

// toSpliced
const spliced = arr.toSpliced(2, 2, 'a', 'b')
console.log(arr)      // [3, 1, 4, 1, 5, 9]
console.log(spliced)  // [3, 1, 'a', 'b', 5, 9]

// with:修改指定索引
const modified = arr.with(0, 'first')
console.log(arr)       // [3, 1, 4, 1, 5, 9]
console.log(modified)  // ['first', 1, 4, 1, 5, 9]

Symbols 作为 WeakMap 键

const weak = new WeakMap()

// 之前:只能用对象作为键
const objKey = {}
weak.set(objKey, 'value')

// 现在:可以用 Symbol
const symKey = Symbol('key')
weak.set(symKey, 'value')

console.log(weak.get(symKey))  // value

ES2024 新特性

Promise.withResolvers

// 之前
let resolve, reject
const promise = new Promise((res, rej) => {
  resolve = res
  reject = rej
})

// 现在
const { promise, resolve, reject } = Promise.withResolvers()

// 使用场景:事件包装
function waitForEvent(emitter, event) {
  const { promise, resolve } = Promise.withResolvers()
  emitter.once(event, resolve)
  return promise
}

数组分组(正式版)

const numbers = [1, 2, 3, 4, 5, 6]

const grouped = Object.groupBy(numbers, n => n % 2 === 0 ? 'even' : 'odd')
// { odd: [1, 3, 5], even: [2, 4, 6] }

String isWellFormed / toWellFormed

// 检查字符串是否为有效的 UTF-16
const str = '东巴文'
console.log(str.isWellFormed())  // true

const invalid = 'test\uD800'
console.log(invalid.isWellFormed())  // false

// 转换为有效的 UTF-16
const fixed = invalid.toWellFormed()
console.log(fixed.isWellFormed())  // true

提案中的特性

Record 和 Tuple(Stage 2)

// 不可变数据结构
const record = #{
  name: '东巴文',
  age: 18
}

const tuple = #[1, 2, 3]

// 深度比较
#{ a: 1 } === #{ a: 1 }  // true
#[1, 2] === #[1, 2]      // true

// 不可变更新
const updated = #{ ...record, age: 19 }

模式匹配(Stage 1)

// 类似于其他语言的模式匹配
const result = match(value) {
  when { type: 'success', data } => data,
  when { type: 'error', message } => throw new Error(message),
  when _ => 'unknown'
}

装饰器(Stage 3)

// 类装饰器
@logged
class User {
  @readonly
  name = '东巴文'
  
  @validate
  setAge(age) {
    this.age = age
  }
}

function logged(target) {
  return class extends target {
    constructor(...args) {
      console.log('创建实例')
      super(...args)
    }
  }
}

function readonly(target, key, descriptor) {
  descriptor.writable = false
  return descriptor
}

Set 方法(Stage 3)

const setA = new Set([1, 2, 3])
const setB = new Set([2, 3, 4])

// 交集
setA.intersection(setB)   // Set { 2, 3 }

// 并集
setA.union(setB)          // Set { 1, 2, 3, 4 }

// 差集
setA.difference(setB)     // Set { 1 }

// 对称差集
setA.symmetricDifference(setB)  // Set { 1, 4 }

// 子集判断
setA.isSubsetOf(setB)     // false
setA.isSupersetOf(setB)   // false
setA.isDisjointFrom(setB) // false

Temporal API(Stage 3)

// 更好的日期时间 API
const now = Temporal.Now.plainDateTimeISO()
console.log(now.toString())  // 2024-01-15T10:30:00

// 创建日期
const date = Temporal.PlainDate.from('2024-01-15')

// 时间运算
const tomorrow = date.add({ days: 1 })
const nextMonth = date.add({ months: 1 })

// 时区支持
const zoned = Temporal.ZonedDateTime.from({
  year: 2024,
  month: 1,
  day: 15,
  hour: 10,
  timeZone: 'Asia/Shanghai'
})

// 持续时间
const duration = Temporal.Duration.from({ hours: 2, minutes: 30 })

Web API 发展

Web Components

// 自定义元素
class DongbaButton extends HTMLElement {
  constructor() {
    super()
    this.attachShadow({ mode: 'open' })
    this.shadowRoot.innerHTML = `
      <style>
        button {
          background: #1890ff;
          color: white;
          border: none;
          padding: 8px 16px;
          border-radius: 4px;
        }
      </style>
      <button><slot></slot></button>
    `
  }
}

customElements.define('dongba-button', DongbaButton)

Web APIs

// View Transitions API
document.startViewTransition(() => {
  // 更新 DOM
  updateContent()
})

// File System Access API
const handle = await window.showOpenFilePicker()
const file = await handle.getFile()
const contents = await file.text()

// Screen Wake Lock API
const wakeLock = await navigator.wakeLock.request('screen')

// Web Share API
await navigator.share({
  title: '东巴文',
  text: '分享内容',
  url: 'https://db-w.cn'
})

// Clipboard API
await navigator.clipboard.writeText('复制的内容')
const text = await navigator.clipboard.readText()

学习建议

关注新特性

  1. TC39 提案仓库:github.com/tc39/proposals
  2. V8 博客:v8.dev/blog
  3. MDN Web Docs:developer.mozilla.org

使用新特性

// 检查特性支持
if ('groupBy' in Object) {
  // 使用新特性
} else {
  // 降级方案
}

// 或使用 polyfill
import 'core-js/actual/array/group-by'

渐进增强

// 使用 Babel 转译新语法
// 使用 core-js 提供 polyfill
// 使用特性检测保证兼容性

JavaScript 发展趋势

语言层面

  • 更好的不可变数据支持
  • 更强大的模式匹配
  • 更完善的类型系统(可选)
  • 更简洁的异步编程

生态层面

  • TypeScript 成为标准
  • 边缘计算和 Serverless
  • WebAssembly 深度集成
  • 跨平台开发统一

工具层面

  • 更快的构建工具
  • 更智能的 IDE 支持
  • 更完善的测试工具
  • 更好的调试体验

东巴文(db-w.cn)—— 与 JavaScript 共同成长

恭喜你完成了 JavaScript 教程的全部学习!从基础语法到高级特性,从浏览器环境到 Node.js 服务端,从代码质量到最佳实践,你已经掌握了现代 JavaScript 开发的核心知识。继续实践,不断探索,成为一名优秀的 JavaScript 开发者!